<script lang="ts">
	import { onMount, tick } from 'svelte';
	import {
		LitAuthClient,
		BaseProvider,
		GoogleProvider,
		isSignInRedirect,
		getProviderFromUrl
	} from '@lit-protocol/lit-auth-client';
	import { LitNodeClient } from '@lit-protocol/lit-node-client';
	import { IRelayPKP } from '@lit-protocol/types';
	import { ProviderType } from '@lit-protocol/constants';
	import { LitAccessControlConditionResource, LitAbility } from '@lit-protocol/auth-helpers';
	import { createMessage } from '$lib/services/messages';

	const redirectUri = 'http://localhost:5173/';
	let view = 'sign_in';
	let error;
	let litAuthClient;
	let litNodeClient;
	let currentProviderType;
	let authMethod;
	let pkps = [];
	let currentPKP;
	let sessionSigs;
	let isLoading = false;

	async function authWithGoogle() {
		isLoading = true;
		error = null;
		try {
			const provider = litAuthClient.initProvider<GoogleProvider>(ProviderType.Google);
			await provider.signIn();
			await handleRedirect(ProviderType.Google);
		} catch (err) {
			error = err;
			view = 'ERROR';
		} finally {
			isLoading = false;
		}
	}

	async function handleRedirect(providerName: string) {
		isLoading = true;
		createMessage({
			text: `Handling redirect for ${providerName}`,
			sender: '$lib/components/GoogleAuth.svelte',
			type: 'SYSTEM'
		});
		try {
			console.log('Handling redirect...');
			let provider: BaseProvider | undefined;

			if (providerName === ProviderType.Google) {
				provider = litAuthClient.getProvider(ProviderType.Google);
			}

			if (!provider) {
				throw new Error('Invalid provider.');
			}

			currentProviderType = providerName as ProviderType;

			// Get auth method object that has the OAuth token from redirect callback
			authMethod = await provider.authenticate();
			await tick(); // Allow Svelte to update the view

			// Fetch PKPs associated with social account
			view = 'fetching';
			const fetchedPkps: IRelayPKP[] = await provider.fetchPKPsThroughRelayer(authMethod);
			await tick(); // Allow Svelte to update the view

			if (fetchedPkps.length > 0) {
				pkps = fetchedPkps;
				view = 'fetched';
			} else {
				view = 'NO_PKPS';
			}
		} catch (err) {
			console.error(err);
			error = err;
			view = 'ERROR';
		} finally {
			isLoading = false;
		}
		console.log(`Handling redirect for ${providerName}`);
		console.log(`Fetched PKPs: ${pkps.length}`);
		createMessage({
			text: `Fetched PKPs: ${pkps.length}`,
			sender: '$lib/components/GoogleAuth.svelte',
			type: 'SYSTEM'
		});
	}
	async function mint() {
		isLoading = true;
		error = null;
		try {
			console.log('Minting started...');
			createMessage({
				text: 'Minting started...',
				sender: '$lib/components/GoogleAuth.svelte',
				type: 'SYSTEM'
			});
			view = 'MINTING';

			const provider = litAuthClient.getProvider(currentProviderType);
			const txHash: string = await provider.mintPKPThroughRelayer(authMethod);
			const response = await provider.relay.pollRequestUntilTerminalState(txHash);
			if (response.status !== 'Succeeded') {
				throw new Error('Minting failed');
			}
			const newPKP: IRelayPKP = {
				tokenId: response.pkpTokenId,
				publicKey: response.pkpPublicKey,
				ethAddress: response.pkpEthAddress
			};

			pkps = [...pkps, newPKP];

			await createSession(newPKP); // Moved the call to createSession() here
			view = 'MINTED'; // Update the view after the session is created
		} catch (err) {
			console.error(err);
			error = err;
			view = 'ERROR';
		} finally {
			isLoading = false;
		}
		console.log('Minted a new PKP.');
		createMessage({
			text: 'Minted a new PKP.',
			sender: '$lib/components/GoogleAuth.svelte',
			type: 'SYSTEM'
		});
	}

	async function createSession(pkp: IRelayPKP) {
		isLoading = true;
		error = null;
		try {
			console.log('Creating session...');
			createMessage({
				text: 'Creating session...',
				sender: '$lib/components/GoogleAuth.svelte',
				type: 'SYSTEM'
			});
			view = 'CREATING_SESSION';

			const litResource = new LitAccessControlConditionResource('*');
			const provider = litAuthClient.getProvider(currentProviderType);
			sessionSigs = await provider.getSessionSigs({
				pkpPublicKey: pkp.publicKey,
				authMethod,
				sessionSigsParams: {
					chain: 'ethereum',
					resourceAbilityRequests: [
						{
							resource: litResource,
							ability: LitAbility.PKPSigning
						}
					]
				}
			});
			currentPKP = pkp;
			createMessage({
				text: 'Session created.',
				sender: '$lib/components/GoogleAuth.svelte',
				type: 'SYSTEM'
			});
			view = 'SESSION_CREATED';
		} catch (err) {
			console.error(err);
			error = err;
			view = 'ERROR';
		} finally {
			isLoading = false;
		}

		console.log('Session created.');
		view = 'SESSION_CREATED';
	}

	onMount(async () => {
		isLoading = true;
		console.log('Component mounted.');
		createMessage({
			text: 'Component mounted.',
			sender: '$lib/components/GoogleAuth.svelte',
			type: 'SYSTEM'
		});
		try {
			litNodeClient = new LitNodeClient({
				litNetwork: 'serrano',
				debug: false
			});
			await litNodeClient.connect();

			litAuthClient = new LitAuthClient({
				litRelayConfig: {
					relayApiKey: 'test-api-key'
				},
				litNodeClient
			});

			litAuthClient.initProvider<GoogleProvider>(ProviderType.Google);

			console.log('Checking if isSignInRedirect...');
			if (!authMethod && isSignInRedirect(redirectUri)) {
				console.log('Redirect detected, handling...');
				createMessage({
					text: 'Redirect detected, handling...',
					sender: '$lib/components/GoogleAuth.svelte',
					type: 'SYSTEM'
				});
				const providerName = getProviderFromUrl();
				if (providerName) {
					await handleRedirect(providerName);
				} else {
					console.error('No provider detected in the URL.');
				}
			} else {
				console.log('No redirect detected.');
				createMessage({
					text: 'No redirect detected.',
					sender: '$lib/components/GoogleAuth.svelte',
					type: 'SYSTEM'
				});
			}
		} catch (err) {
			console.error(err);
			error = err;
			view = 'ERROR';
		} finally {
			isLoading = false;
		}
	});
	function resetView() {
		view = authMethod ? 'fetched' : 'sign_in';
		error = null;
	}
</script>

<main>
	{#if error}
		<h1>Error</h1>
		<p>{error.message}</p>
		<button on:click={() => resetView()}>Got it</button>
	{:else if isLoading}
		<h1>Loading...</h1>
	{:else if view === 'sign_in'}
		<h1>Sign in with Lit</h1>
		<button on:click={authWithGoogle}>Google</button>
	{:else if view === 'HANDLE_REDIRECT'}
		<h1>Handling Google Authentication...</h1>
	{:else if view === 'fetching'}
		<h1>Fetching your PKPs...</h1>
	{:else if view === 'NO_PKPS'}
		<h1>No PKPs found.</h1>
		<button on:click={mint}>Mint a PKP</button>
	{:else if view === 'fetched'}
		<h1>Select a PKP to continue</h1>
		<div>
			{#each pkps as pkp}
				<button on:click={async () => await createSession(pkp)}>
					{pkp.ethAddress}
				</button>
			{/each}
		</div>
	{:else if view === 'MINTING'}
		<h1>Minting your PKP...</h1>
	{:else if view === 'MINTED'}
		<h1>Minted!</h1>
	{:else if view === 'CREATING_SESSION'}
		<h1>Creating session...</h1>
	{:else if view === 'SESSION_CREATED'}
		<h1>Ready for the open web</h1>
		<div>
			<p>Check out your PKP:</p>
			<p>{currentPKP.ethAddress}</p>
		</div>
	{/if}
</main>
