import { ChangeEvent, useEffect, useState } from 'react';
import { IoCheckmark, IoShieldCheckmarkOutline } from 'react-icons/io5';
import { Button, Input, Spinner } from '@chakra-ui/react';

import { getWorksheetNames } from '../../../../common/api/sheets';
import { maybeAxiosError } from '../../../../common/api/utils';
import CopyTag from '../../../../common/components/copy-tag/CopyTag';
import { openLink } from '../../../../common/utils/linkUtils';
import * as Panel from '../../panel-utils/PanelUtils';

import useGoogleSheet from './useGoogleSheet';
import { useSheetStore } from './useSheetStore';

interface GSheetSetupProps {
  onCancel: () => void;
}

export default function GSheetSetup(props: GSheetSetupProps) {
  const { onCancel } = props;

  const { revoke, connect, verifyAuth } = useGoogleSheet();
  const [file, setFile] = useState<File | null>(null);
  const [authKey, setAuthKey] = useState<string | null>(null);
  const [loading, setLoading] = useState<'' | 'cancel' | 'connect' | 'authenticate'>('');
  const [authLink, setAuthLink] = useState('');

  const sheetId = useSheetStore((state) => state.sheetId);
  const setSheetId = useSheetStore((state) => state.setSheetId);
  const setWorksheets = useSheetStore((state) => state.setWorksheets);
  const patchStepData = useSheetStore((state) => state.patchStepData);
  const authenticationStatus = useSheetStore((state) => state.authenticationStatus);
  const setAuthenticationStatus = useSheetStore((state) => state.setAuthenticationStatus);
  const authenticationError = useSheetStore((state) => state.stepData.authenticate.error);

  /** Check if we are authenticated */
  const getAuthStatus = async () => {
    const result = await verifyAuth();
    if (result) {
      setAuthenticationStatus(result.authenticated);
    }
  };

  /** check if the current session has been authenticated */
  useEffect(() => {
    patchStepData({ authenticate: { available: false, error: '' } });
    untilAuthenticated();
  }, []);

  // user cancels the flow
  const handleRevoke = async () => {
    setLoading('cancel');
    await revoke();
    await getAuthStatus();
    setLoading('');
  };

  const handleCancelFlow = () => {
    onCancel();
  };

  /**
   * Gets file from input
   */
  const handleClientSecret = (event: ChangeEvent<HTMLInputElement>) => {
    if (!event.target.files?.length) {
      return;
    }
    setFile(event.target.files[0]);
  };

  /**
   * Requests connection to google auth
   */
  const handleConnect = async () => {
    if (!file) return;
    if (!sheetId) return;
    patchStepData({ worksheet: { available: false, error: '' } });

    setLoading('connect');
    const result = await connect(file, sheetId);
    if (result) {
      setAuthLink(result.verification_url);
      setAuthKey(result.user_code);
    }
    setLoading('');
  };

  const untilAuthenticated = async (attempts: number = 0) => {
    const result = await verifyAuth();
    if (result?.authenticated) {
      setAuthenticationStatus(result.authenticated);
      if (result.authenticated !== 'pending') {
        if (result.authenticated == 'authenticated') {
          try {
            const names = await getWorksheetNames(result.sheetId);
            setWorksheets(names);
          } catch (error) {
            const message = maybeAxiosError(error);
            patchStepData({ worksheet: { available: false, error: message } });
          }
        }
        setLoading('');
        return;
      }
    }
    if (attempts <= 10) {
      setTimeout(() => untilAuthenticated(attempts + 1), 2000);
      return;
    }
    setLoading('');
  };

  /**
   * Open google auth
   */
  const handleAuthenticate = async () => {
    setLoading('authenticate');

    // open link and schedule a check for when the user focuses again
    openLink(authLink);
    window.addEventListener(
      'focus',
      async () => {
        untilAuthenticated();
      },
      { once: true },
    );
  };

  const canConnect = file && sheetId;
  const canAuthenticate = Boolean(authKey) && Boolean(authLink);
  const isLoading = Boolean(loading);
  const isAuthenticated = authenticationStatus === 'authenticated';
  const isAuthenticating = authenticationStatus === 'pending';

  return (
    <Panel.Section>
      <Panel.Title>
        Sync with Google Sheet (experimental)
        {isAuthenticated ? (
          <Button variant='ontime-subtle' size='sm' onClick={handleRevoke} isLoading={loading === 'cancel'}>
            Revoke Authentication
          </Button>
        ) : (
          <Button variant='ontime-subtle' size='sm' onClick={handleCancelFlow}>
            Go Back
          </Button>
        )}
      </Panel.Title>
      <Panel.ListGroup>
        <Panel.Description>Upload Client Secret provided by Google</Panel.Description>
        <Panel.Error>{authenticationError}</Panel.Error>
        <Input
          type='file'
          onChange={handleClientSecret}
          accept='.json'
          size='sm'
          variant='ontime-filled'
          isDisabled={isLoading || canAuthenticate}
        />
      </Panel.ListGroup>
      <Panel.ListGroup>
        <Panel.Description>Enter ID of sheet to synchronise</Panel.Description>
        <Panel.Error>{undefined}</Panel.Error>
        <Input
          size='sm'
          variant='ontime-filled'
          autoComplete='off'
          placeholder='Sheet ID'
          onChange={(event) => setSheetId(event.target.value)}
          isDisabled={isLoading || canAuthenticate}
        />
      </Panel.ListGroup>
      {!canAuthenticate ? (
        <Panel.ListGroup>
          <Panel.InlineElements>
            <Button
              variant='ontime-subtle'
              size='sm'
              leftIcon={<IoCheckmark />}
              onClick={handleConnect}
              isDisabled={!canConnect || isLoading}
              isLoading={loading === 'connect'}
            >
              Connect
            </Button>
          </Panel.InlineElements>
        </Panel.ListGroup>
      ) : (
        <Panel.ListGroup>
          <Panel.InlineElements>
            {isAuthenticating && <Spinner />}
            <CopyTag copyValue={authKey ?? ''} label='Google Auth Key' disabled={!canAuthenticate} size='sm'>
              {authKey ? authKey : 'Upload files to generate Auth Key'}
            </CopyTag>
            <Button
              variant='ontime-filled'
              size='sm'
              leftIcon={<IoShieldCheckmarkOutline />}
              onClick={handleAuthenticate}
              isDisabled={!canAuthenticate}
            >
              Authenticate
            </Button>
          </Panel.InlineElements>
        </Panel.ListGroup>
      )}
    </Panel.Section>
  );
}
