import { useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import * as uint8arrays from 'uint8arrays'
import * as RootKey from '@oddjs/odd/common/root-key'
import * as UCAN from "@oddjs/odd/ucan/index"

import { filesystemStore, sessionStore } from '../../../stores'
import {
  RECOVERY_STATES,
  USERNAME_STORAGE_KEY,
  loadAccount,
  prepareUsername
} from '../../../lib/auth/account'
import Check from '../../icons/CheckIcon'
import RecoveryKitButton from './RecoveryKitButton'

const HasRecoveryKit = () => {
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [_, setFilesystem] = useRecoilState(filesystemStore)
  const session = useRecoilValue(sessionStore)

  const [state, setState] = useState<RECOVERY_STATES>(
    session.session ? RECOVERY_STATES.Done : RECOVERY_STATES.Ready
  );

    /**
   * Parse the user's `username` and `readKey` from the uploaded recovery kit and pass them into
   * odd to recover the user's account and populate the `session` and `filesystem` stores
   * @param files
   */
  const handleFileInput: (
    files: FileList
  ) => Promise<void> = async files => {
    const reader = new FileReader()
    reader.onload = async event => {
      setState(RECOVERY_STATES.Processing)
      try {
        const {
          authStrategy,
          program: {
            components: { crypto, reference, storage },
          },
        } = session;

        const parts = (event.target.result as string)
          .split("username: ")[1]
          .split("key: ");
        const readKey = uint8arrays.fromString(
          parts[1].replace(/(\r\n|\n|\r)/gm, ""),
          "base64pad"
        );

        const oldUsername = parts[0].replace(/(\r\n|\n|\r)/gm, "");
        const hashedOldUsername = await prepareUsername(oldUsername);
        const newRootDID = await session.program.agentDID();

        // Construct a new username using the old `trimmed` name and `newRootDID`
        const newUsername = `${oldUsername.split("#")[0]}#${newRootDID}`;
        const hashedNewUsername = await prepareUsername(newUsername);

        storage.setItem(USERNAME_STORAGE_KEY, newUsername);

        // Register the user with the `hashedNewUsername`
        const { success } = await authStrategy.register({
          username: hashedNewUsername,
        });
        if (!success) {
          throw new Error("Failed to register new user");
        }

        // Build an ephemeral UCAN to allow the
        const proof: string | null = await storage.getItem(
          storage.KEYS.ACCOUNT_UCAN
        );
        const ucan = await UCAN.build({
          dependencies: session.program.components,
          potency: "APPEND",
          resource: "*",
          proof: proof ? proof : undefined,
          lifetimeInSeconds: 60 * 3, // Three minutes
          audience: newRootDID,
          issuer: newRootDID,
        });

        const oldRootCID = await reference.dataRoot.lookup(hashedOldUsername);

        // Update the dataRoot of the new user
        await reference.dataRoot.update(oldRootCID, ucan);

        // Store the accountDID and readKey in odd so they can be used internally load the file system
        await RootKey.store({
          accountDID: newRootDID,
          readKey,
          crypto: crypto,
        });

        // Load account data into sessionStore
        await loadAccount(hashedNewUsername, newUsername);

        setState(RECOVERY_STATES.Done);
      } catch (error) {
        console.error(error)
        setState(RECOVERY_STATES.Error)
      }
    }
    reader.onerror = error => {
      console.error(error)
      setState(RECOVERY_STATES.Error)
    }
    reader.readAsText(files[0])
  }


  return (
    <div
      className="min-h-[calc(100vh-96px)] flex flex-col items-start justify-center max-w-[590px] m-auto gap-6 pb-5 text-sm"
    >
      <h1 className="text-xl">Recover your account</h1>

      {state === RECOVERY_STATES.Done ? (
        <>
          <h3 className="flex items-center gap-2 font-normal text-base text-green-600">
            <Check /> Account recovered!
          </h3>
          <p>
            Welcome back <strong>{session.username.trimmed}.</strong>
            We were able to successfully recover all of your private data.
          </p>
        </>
      ) : (
        <p>
          If you’ve lost access to all of your connected devices, you can use your
          recovery kit to restore access to your private data.
        </p>
      )}

      {state === RECOVERY_STATES.Error && (
        <p className="text-red-600">
          We were unable to recover your account. Please double check that you
          uploaded the correct file.
        </p>
      )}

      <div className="flex flex-col gap-2">
        <RecoveryKitButton handleFileInput={handleFileInput} state={state} />

        {state !== RECOVERY_STATES.Done && (
          <p className="text-xxs">
            {`It should be a file named ODD-RecoveryKit-{yourUsername}.txt`}
          </p>
        )}
      </div>
    </div>
  )
}

export default HasRecoveryKit