import React, { ReactElement, useEffect, useState } from 'react';
import './index.scss';
import Stepper from '@mui/material/Stepper';
import Step from '@mui/material/Step';
import Box from '@mui/material/Box';
import StepLabel from '@mui/material/StepLabel';
import classNames from 'classnames';
import type { PresentationJSON } from 'tlsn-js/build/types';
import Button from '../Button';
import ConfettiExplosion, { ConfettiProps } from 'react-confetti-explosion';

const steps = [
  'Connect Extension',
  'Install Plugin',
  'Run Plugin',
  '🎉 Claim POAP 🎉',
];

export default function Steps(): ReactElement {
  const [extensionInstalled, setExtensionInstalled] = useState(false);
  const [pluginID, setPluginID] = useState('');
  const [step, setStep] = useState<number>(0);
  const [client, setClient] = useState<any>(null);
  const [pluginData, setPluginData] = useState<PresentationJSON | null>(null);
  const [loading, setLoading] = useState<boolean>(false);
  const [pluginInstalled, setPluginInstalled] = useState<boolean>(false);
  const [transcript, setTranscript] = useState<any>(null);
  const [screenName, setScreenName] = useState<string>('');
  const [exploding, setExploding] = useState<boolean>(false);

  useEffect(() => {
    const checkExtension = () => {
      //@ts-ignore
      if (typeof window.tlsn !== 'undefined') {
        setExtensionInstalled(true);
        setTimeout(async () => {
          // temporary fix until extension events added
          // @ts-ignore
          setClient(await window.tlsn.connect());
          setStep(1);
        }, 200);
      } else {
        return;
      }
    };

    window.onload = () => {
      checkExtension();
    };

    (async () => {
      const { default: init } = await import('tlsn-js');
      await init();
    })();

    return () => {
      window.onload = null;
    };
  }, []);

  useEffect(() => {
    if (transcript) {
      const match = transcript.recv.match(/"screen_name":"([^"]+)"/);
      const screenName = match ? match[1] : null;
      setScreenName(screenName);
      setExploding(true);
    }
  }, [transcript]);

  async function handleConnect() {
    try {
      //@ts-ignore
      setClient(await window.tlsn.connect());
      setStep(1);
    } catch (error) {
      console.log(error);
    }
  }

  async function handleGetPlugins() {
    try {
      const plugins = await client.getPlugins('**', '**', {
        id: 'twitter-plugin',
      });
      if (plugins.length > 0) {
        setPluginID(plugins[0].hash);
        setStep(2);
      } else {
        setPluginInstalled(true);
      }
    } catch (error) {
      console.log(error);
    }
  }

  async function handlePluginInstall() {
    try {
      const plugin = await client.installPlugin(
        'https://github.com/tlsnotary/tlsn-extension/raw/main/src/assets/plugins/twitter_profile.wasm',
        { id: 'twitter-plugin' },
      );
      setPluginID(plugin);
      setStep(2);
    } catch (error) {
      console.log(error);
    }
  }

  async function handleRunPlugin() {
    try {
      setLoading(true);
      const pluginData = await client.runPlugin(pluginID);
      setLoading(false);
      setPluginData(pluginData);
      setStep(3);
    } catch (error) {
      setLoading(false);
      console.log(error);
    }
  }

  return (
    <div className="flex flex-col items-center gap-4">
      {extensionInstalled ? (
        <>
          <div className="flex flex-row items-center gap-2 text-slate-600 font-bold pb-2">
            Connected{' '}
            <div
              className={classNames(
                'rounded-full h-[10px] w-[10px] border-[2px]',
                {
                  'bg-green-500': step >= 1,
                  'bg-red-500': step === 0,
                },
              )}
            ></div>
          </div>
          <Box className="w-full max-w-xl mt-6 pb-4">
            <Stepper activeStep={step} alternativeLabel>
              {steps.map((label) => (
                <Step key={label}>
                  <StepLabel>{label}</StepLabel>
                </Step>
              ))}
            </Stepper>
          </Box>
          <div className="flex gap-3">
            {step === 0 && (
              <button onClick={handleConnect} className="button">
                Connect
              </button>
            )}
            {step === 1 && (
              <div className="flex flex-col gap-2">
                <button className="button" onClick={handleGetPlugins}>
                  Check Plugins
                </button>
                <button
                  onClick={handlePluginInstall}
                  disabled={!pluginInstalled}
                  className="button"
                >
                  Install Plugin
                </button>
              </div>
            )}
            {step === 2 && (
              <div className="flex flex-col items-center justify-center gap-2">
                <Button onClick={handleRunPlugin} loading={loading}>
                  Run Plugin
                </Button>
                <span className="font-bold">
                  Please keep the sidebar open during the notarization process
                </span>
              </div>
            )}
            {step === 4 && (
              <>
                <ClaimPoap screen_name={screenName} exploding={exploding} />
              </>
            )}
          </div>

          <DisplayPluginData
            step={step}
            pluginData={pluginData}
            transcript={transcript}
            setTranscript={setTranscript}
            setStep={setStep}
          />
        </>
      ) : (
        <div className="flex flex-col justify-center items-center gap-2">
          <a
            href="https://chromewebstore.google.com/detail/tlsn-extension/gcfkkledipjbgdbimfpijgbkhajiaaph"
            target="_blank"
            className="button"
          >
            Install TLSN Extension
          </a>
          <p className="font-bold">Please install the extension to proceed. </p>
          <p className="font-bold">
            You will need to refresh your browser after installing the
            extension.
          </p>
        </div>
      )}
    </div>
  );
}

function DisplayPluginData({
  step,
  pluginData,
  transcript,
  setTranscript,
  setStep,
}: {
  step: number;
  pluginData: any;
  transcript: any;
  setTranscript: any;
  setStep: any;
}): ReactElement {
  const [tab, setTab] = useState<'sent' | 'recv'>('sent');

  async function handleVerify() {
    try {
      const { Presentation, Transcript } = await import('tlsn-js');
      const presentation = await new Presentation(pluginData.data);
      const proof = await presentation.verify();
      const transcript = new Transcript({
        sent: proof.transcript.sent,
        recv: proof.transcript.recv,
      });
      const verifiedData = {
        sent: transcript.sent(),
        recv: transcript.recv(),
      };
      setTranscript(verifiedData);
      setStep(4);
    } catch (error) {
      console.log(error);
    }
  }

  const formatDataPreview = (data: PresentationJSON) => {
    if (!data) return '';
    return Object.entries(data)
      .map(([key, value]) => {
        if (typeof value === 'object' && value !== null) {
          return `${key}: ${JSON.stringify(value, null, 2)}`;
        } else if (key === 'data') {
          const maxLength = 160;
          const previewData = value.toString().substring(0, maxLength);
          const formattedData = previewData.match(/.{1,20}/g)?.join('\n');
          return `${key}: ${formattedData}... ${value.length} more`;
        } else {
          return `${key}: ${value}`;
        }
      })
      .join('\n');
  };

  return (
    <div className="flex justify-center items-center space-x-4 mt-8">
      <div className="w-96">
        <div className="p-2 bg-gray-200 border-t rounded-t-md text-center text-lg font-semibold">
          Attestation
        </div>
        <div className="p-4 bg-gray-100 border rounded-b-md h-96 text-left overflow-auto">
          <pre className="text-sm text-gray-700 whitespace-pre-wrap text-[12px]">
            {formatDataPreview(pluginData)}
          </pre>
        </div>
      </div>
      <button disabled={step !== 3} onClick={handleVerify} className="button">
        Verify
      </button>
      <div className="w-96">
        <div className="p-2 bg-gray-200 border-t rounded-t-md text-center text-lg font-semibold">
          Presentation
        </div>
        <div className="bg-gray-100 border rounded-b-md h-96 overflow-auto">
          <div className="flex border-b">
            <button
              onClick={() => setTab('sent')}
              className={`p-2 w-1/2 text-center ${tab === 'sent' ? 'bg-slate-500 text-white' : 'bg-white text-black'}`}
            >
              Sent
            </button>
            <button
              onClick={() => setTab('recv')}
              className={`p-2 w-1/2 text-center ${tab === 'recv' ? 'bg-slate-500 text-white' : 'bg-white text-black'}`}
            >
              Received
            </button>
          </div>
          <div className="p-4 text-left">
            <pre className="text-[10px] text-gray-700 whitespace-pre-wrap">
              {transcript &&
                (tab === 'sent' ? transcript.sent : transcript.recv)}
            </pre>
          </div>
        </div>
      </div>
    </div>
  );
}

function ClaimPoap({
  screen_name,
  exploding,
}: {
  screen_name: string;
  exploding: boolean;
}): ReactElement {
  const [screenName, setScreenName] = useState('');
  const [poapLink, setPoapLink] = useState<string>('');
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    const handleClaimPoap = async () => {
      try {
        if (!screen_name) return;
        const response = await fetch('/poap-claim', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({ screenName: screen_name }),
        });
        if (response.status === 200) {
          const data = await response.json();
          setPoapLink(data.poapLink);
        } else {
          setError(await response.text());
        }
      } catch (error) {
        console.log(error);
      }
    };

    handleClaimPoap();
  }, [screen_name]);

  const mediumProps: ConfettiProps = {
    force: 0.6,
    duration: 4000,
    particleCount: 150,
    width: 1500,
    colors: ['#F0FFF', '#F0F8FF', '#483D8B', '#E0FFF', '#778899'],
  };

  return (
    <div>
      {poapLink !== '' && (
        <a className="button" href={poapLink} target="_blank">
          Claim POAP!
        </a>
      )}
      {exploding && <ConfettiExplosion {...mediumProps} />}
    </div>
  );
}
