import React, {
  useState,
  useEffect,
  useContext,
  useMemo,
  useCallback,
} from "react";
import { Block } from "@ethersproject/abstract-provider";
import { FixedNumber } from "@ethersproject/bignumber";
import { Line } from "react-chartjs-2";
import {
  Chart as ChartJS,
  LinearScale,
  CategoryScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip,
} from "chart.js";
import { Transition } from "@headlessui/react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faBurn } from "@fortawesome/free-solid-svg-icons/faBurn";
import { faCoins } from "@fortawesome/free-solid-svg-icons/faCoins";
import { faCube } from "@fortawesome/free-solid-svg-icons/faCube";
import { faGasPump } from "@fortawesome/free-solid-svg-icons/faGasPump";
import { faHistory } from "@fortawesome/free-solid-svg-icons/faHistory";
import BlockRow from "./BlockRow";
import { ExtendedBlock, readBlock } from "../../useErigonHooks";
import { RuntimeContext } from "../../useRuntime";
import {
  burntFeesChartOptions,
  burntFeesChartData,
  gasChartOptions,
  gasChartData,
} from "./chart";

ChartJS.register(
  LinearScale,
  CategoryScale,
  PointElement,
  LineElement,
  Filler,
  Tooltip
);

const MAX_BLOCK_HISTORY = 20;

const PREV_BLOCK_COUNT = 15;

type BlocksProps = {
  latestBlock: Block;
  targetBlockNumber: number;
};

const Blocks: React.FC<BlocksProps> = ({ latestBlock, targetBlockNumber }) => {
  const { provider } = useContext(RuntimeContext);
  const [blocks, setBlocks] = useState<ExtendedBlock[]>([]);
  const [now, setNow] = useState<number>(Date.now());
  const [toggleChart, setToggleChart] = useState<boolean>(true);

  const addBlock = useCallback(
    async (blockNumber: number) => {
      if (!provider) {
        return;
      }

      // Skip blocks before the hard fork during the transition
      if (blockNumber < targetBlockNumber) {
        return;
      }

      const extBlock = await readBlock(provider, blockNumber.toString());
      setNow(Date.now());
      setBlocks((_blocks) => {
        if (_blocks.length > 0 && blockNumber === _blocks[0].number) {
          return _blocks;
        }
        if (extBlock === null) {
          return _blocks;
        }

        // Leave the last block because of transition animation
        const newBlocks = [extBlock, ..._blocks].slice(
          0,
          MAX_BLOCK_HISTORY + 1
        );

        // Little hack to fix out of order block notifications
        newBlocks.sort((a, b) => b.number - a.number);
        return newBlocks;
      });
    },
    [provider, targetBlockNumber]
  );

  useEffect(() => {
    addBlock(latestBlock.number);
  }, [addBlock, latestBlock]);

  const data = useMemo(
    () => (toggleChart ? gasChartData(blocks) : burntFeesChartData(blocks)),
    [toggleChart, blocks]
  );
  const chartOptions = toggleChart ? gasChartOptions : burntFeesChartOptions;

  // On page reload, pre-populate the last N blocks
  useEffect(
    () => {
      const addPreviousBlocks = async () => {
        for (
          let i = latestBlock.number - PREV_BLOCK_COUNT;
          i < latestBlock.number;
          i++
        ) {
          await addBlock(i);
        }
      };

      setBlocks([]);
      addPreviousBlocks();
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    []
  );

  return (
    <div className="w-full flex-grow">
      <div className="px-9 pt-3 pb-12 divide-y-2">
        <div className="relative">
          <div className="flex justify-center items-baseline space-x-2 px-3 pb-2 text-lg text-orange-500 ">
            <span>
              <FontAwesomeIcon icon={faBurn} />
            </span>
            <span>EIP-1559 is activated. Watch the fees burn.</span>
            <span>
              <FontAwesomeIcon icon={faBurn} />
            </span>
          </div>
          <div className="absolute right-0 top-0 border rounded shadow-md px-2 py-1 text-sm text-link-blue hover:bg-gray-50 hover:text-link-blue-hover">
            <button onClick={() => setToggleChart(!toggleChart)}>
              {toggleChart ? "Gas usage" : "Burnt fees"}
            </button>
          </div>
        </div>
        <div>
          <Line data={data} height={100} options={chartOptions} />
        </div>
        <div className="mt-5 grid grid-cols-9 gap-x-2 px-3 py-2">
          <div className="flex space-x-1 items-baseline">
            <span className="text-gray-500">
              <FontAwesomeIcon icon={faCube} />
            </span>
            <span>Block</span>
          </div>
          <div className="text-right flex space-x-1 justify-end items-baseline">
            <span className="text-gray-500">
              <FontAwesomeIcon icon={faGasPump} />
            </span>
            <span>Gas used</span>
          </div>
          <div className="text-right">Gas target</div>
          <div className="text-right">Base fee</div>
          <div className="text-right col-span-2 flex space-x-1 justify-end items-baseline">
            <span className="text-yellow-400">
              <FontAwesomeIcon icon={faCoins} />
            </span>
            <span>Rewards</span>
          </div>
          <div className="text-right col-span-2 flex space-x-1 justify-end items-baseline">
            <span className="text-orange-500">
              <FontAwesomeIcon icon={faBurn} />
            </span>
            <span>Burnt fees</span>
          </div>
          <div className="text-right flex space-x-1 justify-end items-baseline">
            <span className="text-gray-500">
              <FontAwesomeIcon icon={faHistory} />
            </span>
            <span>Age</span>
          </div>
        </div>
        {blocks.map((b, i, all) => (
          <Transition
            key={b.hash}
            show={i < MAX_BLOCK_HISTORY}
            appear
            enter="transition ease-out duration-500"
            enterFrom="opacity-0 -translate-y-10"
            enterTo="opacity-100 translate-y-0"
            leave="transition ease-out duration-1000"
            leaveFrom="opacity-100 translate-y-0"
            leaveTo="opacity-0 translate-y-10"
          >
            <BlockRow
              now={now}
              block={b}
              baseFeeDelta={
                i < all.length - 1
                  ? FixedNumber.from(b.baseFeePerGas!)
                      .divUnsafe(FixedNumber.from(1e9))
                      .round(0)
                      .subUnsafe(
                        FixedNumber.from(all[i + 1].baseFeePerGas!)
                          .divUnsafe(FixedNumber.from(1e9))
                          .round(0)
                      )
                      .toUnsafeFloat()
                  : 0
              }
            />
          </Transition>
        ))}
      </div>
    </div>
  );
};

export default React.memo(Blocks);