import { requestApi } from ':src/utils.ts'
import { startAuthentication } from '@simplewebauthn/browser'
import { PublicKeyCredentialRequestOptionsJSON } from '@simplewebauthn/types'
import type {
	WebAuthnLoginFinishPayload,
	WebAuthnLoginStartPayload,
} from '../routes/api/webauthn/login/[step].ts'
import { Button } from ':components/Button.tsx'
import { Input } from ':components/Input.tsx'
import {
	getStyleScope,
	useSmartStylesheet,
} from ':plugins/SmartStylesheetIsland.tsx'

const scope = getStyleScope(LoginForm)

export default function LoginForm() {
	useSmartStylesheet(import.meta, { scope })

	return (
		<form
			onSubmit={connect}
			method='POST'
			action=''
			class={scope}
		>
			<Input
				label='Email'
				name='email'
				autoComplete='email'
				type='email'
				required
			/>
			<Input
				label='Utiliser une Passkey si disponible'
				name='passkey'
				type='checkbox'
				checked
			/>
			<Button variant='primary'>Me connecter</Button>
		</form>
	)
}

type LoginFormFields = {
	email: string
	passkey: 'on' | undefined
}

async function connect(event: Event) {
	if (!(event instanceof SubmitEvent)) return false
	event.preventDefault()
	const form = event.target as HTMLFormElement
	const fields = formJSON<LoginFormFields>(form)

	try {
		// User disable passkey
		if (fields.passkey !== 'on') {
			throw new Error('User refused passkey')
		}

		// Try PassKey connection
		if (!isWebAuthnSupported()) {
			throw new Error('WebAuthn is not supported by your browser')
		}

		await webAuthnLogin(fields)

		// Reload UI
		location.reload()
	} catch (error) {
		// Check is user stop passkey connection
		if (error instanceof Error && error.name === 'NotAllowedError') {
			form.reset()
			return
		}
		// Else use magic link
		await magicLinkLogin(fields)

		// Reload UI
		location.reload()
	}

	form.reset()
}

async function magicLinkLogin(fields: LoginFormFields) {
	await requestApi('magiclink', 'POST', fields)
	console.log('Un lien de connection vous a été envoyé par mail !')
}

async function webAuthnLogin(fields: LoginFormFields) {
	// Send WebAuthn authentication options
	const authenticationOptions = await requestApi<
		WebAuthnLoginStartPayload,
		PublicKeyCredentialRequestOptionsJSON
	>('webauthn/login/start', 'POST', fields)

	// Pass the options to the authenticator and wait for a response
	const authentication = await startAuthentication(authenticationOptions)

	// Verify authentication
	const verification = await requestApi<
		WebAuthnLoginFinishPayload,
		{ verified: boolean }
	>('webauthn/login/finish', 'POST', authentication)

	// Show UI appropriate for the `verified` status
	if (verification.verified) {
		console.log('Success!')
	} else {
		console.error('PassKey was not verified!')
	}
}

function isWebAuthnSupported(): boolean {
	return 'credentials' in navigator
}

function formJSON<T extends Record<string, unknown>>(form: HTMLFormElement): T {
	const formData = new FormData(form)
	return Object.fromEntries(formData) as unknown as T
}
