import { requestApi } from ':src/utils.ts'
import { startRegistration } from '@simplewebauthn/browser'
import { PublicKeyCredentialCreationOptionsJSON } from '@simplewebauthn/types'
import { Button, Input } from 'univoq'
import type {
	WebAuthnRegisterFinishPayload,
	WebAuthnRegisterStartPayload,
} from '../routes/api/webauthn/register/[step].ts'

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

function RegisterForm({ disabled }: { disabled?: boolean }) {
	return (
		<form onSubmit={register} method='POST' action=''>
			<Input label='Nom de la clé' name='name' required></Input>
			<Button
				label='Enregistrer une PassKey'
				variant='primary'
				disabled={disabled}
			>
				Enregistrer une PassKey
			</Button>
		</form>
	)
}

export default function PassKeyRegister() {
	if (!isWebAuthnSupported()) {
		return (
			<div>
				<span>Erreur: WebAuthn n'est pas supporté par votre navigateur</span>
				<RegisterForm disabled />
			</div>
		)
	}

	return (
		<div>
			<span>Enregistrer une PassKey pour cet appareil</span>
			<RegisterForm />
		</div>
	)
}

type RegisterFormFields = {
	name: string
}
async function register(event: Event) {
	if (!(event instanceof SubmitEvent)) return false
	event.preventDefault()
	const form = event.target as HTMLFormElement
	const fields = formJSON<RegisterFormFields>(form)

	try {
		await webAuthnRegister(fields)
	} catch (cause) {
		console.error(
			new Error('passkey register failed', {
				cause,
			}),
		)
	}
}

async function webAuthnRegister(fields: RegisterFormFields) {
	if (localStorage.getItem('webauthn-registered')) {
		return
	}

	const registrationOptions = await requestApi<
		WebAuthnRegisterStartPayload,
		PublicKeyCredentialCreationOptionsJSON
	>('webauthn/register/start', 'POST', fields)

	// Pass the options to the authenticator and wait for a response
	const registration = await startRegistration(registrationOptions)
		.catch((error) => {
			// Some basic error handling
			if (error.name === 'InvalidStateError') {
				console.error(
					'Authenticator was probably already registered by user',
				)
				return null
			} else {
				throw error
			}
		})

	if (registration === null) return

	// Verify the registration
	try {
		await requestApi<
			WebAuthnRegisterFinishPayload,
			{ verified: boolean }
		>('webauthn/register/finish', 'POST', registration)
		console.log('Success!')
		localStorage.setItem('webauthn-registered', 'true')
	} catch (error) {
		console.error('Oh no, something went wrong! Response:', error)
	}
}

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