<template>
  <UContainer class="page-shell-narrow">
    <div class="grid gap-8 lg:grid-cols-[minmax(0,1fr)_27rem] lg:items-center">
      <section class="page-header">
        <UBadge :label="t('login.badge')" color="primary" variant="soft" class="page-eyebrow" />
        <h1 class="page-title">
          {{ t('login.title') }}
        </h1>
        <p class="page-description">
          {{ t('layout.brand') }}
        </p>

        <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-1">
          <div class="surface-card rounded-lg p-4">
            <div class="flex items-center gap-3">
              <div class="flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
                <UIcon name="i-lucide-lock-keyhole" class="size-5" />
              </div>
              <div>
                <p class="text-sm font-semibold text-highlighted">
                  {{ t('login.signIn') }}
                </p>
                <p class="text-sm text-muted">
                  {{ t('login.remember') }}
                </p>
              </div>
            </div>
          </div>

          <div class="surface-card rounded-lg p-4">
            <div class="flex items-center gap-3">
              <div class="flex size-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
                <UIcon name="i-lucide-fingerprint" class="size-5" />
              </div>
              <div>
                <p class="text-sm font-semibold text-highlighted">
                  {{ t('login.passkey') }}
                </p>
                <p class="text-sm text-muted">
                  {{ t('login.or') }}
                </p>
              </div>
            </div>
          </div>
        </div>
      </section>

      <UCard class="surface-card overflow-hidden rounded-lg">
        <template #header>
          <div class="space-y-1">
            <p class="text-sm font-semibold text-primary">
              {{ t('login.badge') }}
            </p>
            <h2 class="text-xl font-semibold text-highlighted">
              {{ t('login.signIn') }}
            </h2>
          </div>
        </template>

        <UForm :state="form" :validate="validateLogin" class="space-y-5" @submit="onSubmit">
          <UFormField name="username" :label="t('login.username')" required>
            <UInput
              v-model="form.username"
              type="text"
              size="xl"
              class="w-full"
              :placeholder="t('login.usernamePlaceholder')"
            />
          </UFormField>

          <UFormField name="password" :label="t('login.password')" required>
            <UInput
              v-model="form.password"
              type="password"
              size="xl"
              class="w-full"
              :placeholder="t('login.passwordPlaceholder')"
            />
          </UFormField>

          <UCheckbox v-model="form.remember" :label="t('login.remember')" />

          <UButton
            type="submit"
            :label="t('login.signIn')"
            size="xl"
            :loading="passwordPending"
            class="w-full justify-center"
          />
        </UForm>

        <div class="my-6 flex items-center gap-3">
          <div class="h-px flex-1 bg-default" />
          <span class="text-xs font-semibold uppercase text-muted">{{ t('login.or') }}</span>
          <div class="h-px flex-1 bg-default" />
        </div>

        <UButton
          :label="t('login.passkey')"
          color="neutral"
          variant="outline"
          size="xl"
          class="w-full justify-center"
          icon="i-lucide-fingerprint"
          :loading="passkeyPending"
          @click="loginWithPasskey"
        />
      </UCard>
    </div>
  </UContainer>
</template>

<script lang="ts" setup>
import type { FormError, FormSubmitEvent } from '@nuxt/ui'

import { getDefaultAuthenticatedPath } from '~~/shared/auth'

import { getErrorMessage } from '../../utils/errors'

definePageMeta({
  middleware: 'guest'
})

const toast = useToast()
const router = useRouter()
const auth = useAuth()
const apiClient = useApiClient()
const { t } = useLocale()

const form = reactive({
  username: '',
  password: '',
  remember: true
})
const passwordPending = ref(false)
const passkeyPending = ref(false)

function validateLogin(state: typeof form): FormError[] {
  const errors: FormError[] = []

  if (!state.username.trim()) {
    errors.push({ name: 'username', message: t('login.usernameRequired') })
  }

  if (!state.password.trim()) {
    errors.push({ name: 'password', message: t('login.passwordRequired') })
  }

  return errors
}

async function finishLogin(user: Awaited<ReturnType<typeof auth.fetchSession>>) {
  if (!user) {
    return
  }

  await router.push(getDefaultAuthenticatedPath(user))
}

async function onSubmit(event: FormSubmitEvent<typeof form>) {
  event.preventDefault()

  if (passwordPending.value) {
    return
  }

  passwordPending.value = true

  try {
    const response = await apiClient<{ user: typeof auth.user.value }>('/api/auth/login', {
      method: 'POST',
      body: {
        username: form.username,
        password: form.password,
        remember: form.remember
      }
    })

    auth.setUser(response.user)
    await finishLogin(response.user)
  } catch (error: any) {
    toast.add({
      title: t('login.failed'),
      description: getErrorMessage(error, t('login.failedDescription')),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    passwordPending.value = false
  }
}

async function loginWithPasskey() {
  if (passkeyPending.value) {
    return
  }

  passkeyPending.value = true

  try {
    const { browserSupportsWebAuthn, startAuthentication } = await import('@simplewebauthn/browser')

    if (!browserSupportsWebAuthn()) {
      throw new Error('This browser does not support WebAuthn passkeys.')
    }

    const optionsResponse = await apiClient<{
      options: Record<string, any>
      challengeToken: string
    }>('/api/auth/passkey/login/options', {
      method: 'POST'
    })
    const credential = await startAuthentication({
      optionsJSON: optionsResponse.options
    })
    const verification = await apiClient<{ user: typeof auth.user.value }>('/api/auth/passkey/login/verify', {
      method: 'POST',
      body: {
        response: credential,
        challengeToken: optionsResponse.challengeToken,
        remember: form.remember
      }
    })

    auth.setUser(verification.user)
    await finishLogin(verification.user)
  } catch (error: any) {
    toast.add({
      title: t('login.passkeyFailed'),
      description: getErrorMessage(error, t('login.passkeyFailedDescription')),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    passkeyPending.value = false
  }
}
</script>
