import React, { useMemo } from "react";
import { Log } from "@ethersproject/abstract-provider";
import { Fragment, Interface, LogDescription } from "@ethersproject/abi";
import { Tab } from "@headlessui/react";
import TransactionAddress from "../components/TransactionAddress";
import Copy from "../components/Copy";
import ModeTab from "../components/ModeTab";
import DecodedParamsTable from "./decoder/DecodedParamsTable";
import DecodedLogSignature from "./decoder/DecodedLogSignature";
import { useTopic0 } from "../useTopic0";
import { ResolvedAddresses } from "../api/address-resolver";
import { ChecksummedAddress } from "../types";
import { Metadata } from "../sourcify/useSourcify";

type LogEntryProps = {
  log: Log;
  logDesc: LogDescription | null | undefined;
  resolvedAddresses: ResolvedAddresses | undefined;
  metadatas: Record<ChecksummedAddress, Metadata | null | undefined>;
};

const LogEntry: React.FC<LogEntryProps> = ({
  log,
  logDesc,
  resolvedAddresses,
  metadatas,
}) => {
  const rawTopic0 = log.topics[0];
  const topic0 = useTopic0(rawTopic0);

  const topic0LogDesc = useMemo(() => {
    if (!topic0) {
      return topic0;
    }
    if (!topic0.signatures) {
      return undefined;
    }

    const sigs = topic0.signatures;
    for (const sig of sigs) {
      const logFragment = Fragment.fromString(`event ${sig}`);
      const intf = new Interface([logFragment]);
      try {
        return intf.parseLog(log);
      } catch (err) {
        // Ignore on purpose; try to match other sigs
      }
    }
    return undefined;
  }, [topic0, log]);

  const resolvedLogDesc = logDesc ?? topic0LogDesc;

  return (
    <div className="flex space-x-10 py-5">
      <div>
        <span className="rounded-full w-12 h-12 flex items-center justify-center bg-green-50 text-green-500">
          {log.logIndex}
        </span>
      </div>
      <div className="w-full space-y-2">
        <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
          <div className="font-bold text-right">Address</div>
          <div className="col-span-11 mr-auto">
            <div className="flex items-baseline space-x-2 -ml-1 mr-3">
              <TransactionAddress
                address={log.address}
                resolvedAddresses={resolvedAddresses}
                metadata={metadatas[log.address]}
              />
              <Copy value={log.address} />
            </div>
          </div>
        </div>
        <Tab.Group>
          <Tab.List className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
            <div className="text-right">Parameters</div>
            <div className="col-span-11 flex space-x-1 mb-1">
              <ModeTab>Decoded</ModeTab>
              <ModeTab>Raw</ModeTab>
            </div>
          </Tab.List>
          <Tab.Panels as={React.Fragment}>
            <Tab.Panel className="space-y-2">
              {resolvedLogDesc === undefined ? (
                <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
                  <div className="col-start-2 flex space-x-2 items-center col-span-11">
                    Waiting for data...
                  </div>
                </div>
              ) : resolvedLogDesc === null ? (
                <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
                  <div className="col-start-2 flex space-x-2 items-center col-span-11">
                    Can't decode data
                  </div>
                </div>
              ) : (
                <>
                  <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
                    <div className="col-start-2 flex space-x-2 items-center col-span-11 font-mono">
                      <DecodedLogSignature
                        event={resolvedLogDesc.eventFragment}
                      />
                    </div>
                  </div>
                  <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
                    <div className="col-start-2 flex space-x-2 items-center col-span-11">
                      <DecodedParamsTable
                        args={resolvedLogDesc.args}
                        paramTypes={resolvedLogDesc.eventFragment.inputs}
                        hasParamNames={resolvedLogDesc === logDesc}
                        resolvedAddresses={resolvedAddresses}
                      />
                    </div>
                  </div>
                </>
              )}
            </Tab.Panel>
            <Tab.Panel className="space-y-2">
              {log.topics.map((t, i) => (
                <div
                  className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm"
                  key={i}
                >
                  <div className="text-right">{i === 0 && "Topics"}</div>
                  <div className="flex space-x-2 items-center col-span-11 font-mono">
                    <span className="rounded bg-gray-100 text-gray-500 px-2 py-1 text-xs">
                      {i}
                    </span>
                    <span>{t}</span>
                  </div>
                </div>
              ))}
              <div className="grid grid-cols-12 gap-x-3 gap-y-5 text-sm">
                <div className="text-right pt-2">Data</div>
                <div className="col-span-11">
                  <textarea
                    className="w-full h-40 bg-gray-50 font-mono focus:outline-none border rounded p-2"
                    value={log.data}
                    readOnly
                  />
                </div>
              </div>
            </Tab.Panel>
          </Tab.Panels>
        </Tab.Group>
      </div>
    </div>
  );
};

export default React.memo(LogEntry);