import { Head, useForm, usePage } from '@inertiajs/react'
import { CircleAlert } from 'lucide-react'
import type { FormEvent } from 'react'
import { useEffect, useRef } from 'react'

import { FieldError, fieldErrorProps } from '@/components/FieldError'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
import { Field, FieldGroup, FieldLabel } from '@/components/ui/field'
import { Input } from '@/components/ui/input'
import { faultText } from '@/lib/errors'
import { t } from '@/lib/i18n'
import { route } from '@/lib/routes'

/**
 * Ingreso con correo y contraseña.
 *
 * El error de credenciales no distingue entre «ese correo no existe» y «la
 * contraseña no es ésa»: separarlos convertiría este formulario en una forma de
 * averiguar qué correos están registrados. De esa ambigüedad deliberada sale
 * todo lo demás: como el mensaje habla de **dos** campos, no puede colgar de
 * uno, así que llega del servidor en `errors.form`, se rinde arriba de los
 * campos, marca los dos y se lleva el foco (RT-08).
 *
 * Es la única pantalla del producto que **no** usa `AppLayout` y la única que
 * rinde su propio `<h1>`. Está bien que sea así —todavía no hay cuenta, así que
 * no hay barra lateral, ni encabezado, ni avisos de nivel cuenta— y la excepción
 * está escrita en el contrato, en la regla verificable 1, para que nadie la
 * «arregle».
 *
 * **También es la única que se dibuja sin cuenta de la cual leer el idioma.** Lo
 * resuelve la cookie que dejó la última visita; sin cookie, inglés.
 */
export default function Login({ next }: { next: string }) {
  const { errors } = usePage().props
  // El destino se reenvía como campo del formulario. La dirección lo trae en la
  // cadena de consulta, pero el envío va a «/login» a secas: si no viajara acá,
  // quien llegó por un enlace terminaría en el listado en vez de en la página
  // que estaba buscando.
  const form = useForm({ email: '', password: '', next })

  const failed = errors.form
  const alertRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    // El foco va al error cuando llega. `role="alert"` alcanza para que se
    // anuncie, pero quien navega con teclado queda parado donde estaba y tiene
    // que bajar a buscar qué pasó (RT-15).
    if (failed) alertRef.current?.focus()
  }, [failed])

  const submit = (event: FormEvent) => {
    event.preventDefault()
    // La contraseña se descarta del estado del formulario al terminar, salga
    // bien o mal: no tiene por qué sobrevivir en memoria a la navegación.
    form.post(route('login'), { onFinish: () => form.reset('password') })
  }

  return (
    <div className="bg-background text-foreground flex min-h-screen items-center justify-center px-4">
      <Head title={t('login.title')} />

      <div className="flex w-full max-w-sm flex-col gap-6">
        {/*
          Acá **no** va un cartel explicando que la página pedida necesita
          cuenta. Se probó y se sacó: llegar a un formulario de ingreso ya
          explica por sí solo qué hay que hacer, y ningún producto conocido lo
          anuncia. El destino se sigue conservando en el campo oculto de abajo,
          que es lo único que hacía falta de `next`: quien entra aterriza donde
          quería ir, sin que nadie se lo tenga que contar antes.
        */}
        <div className="flex flex-col gap-2 text-center">
          <h1 className="text-2xl font-semibold tracking-tight">{t('brand')}</h1>
          {/*
            La bajada describe la plataforma y no una herramienta. Decía
            «sincronización de sitemaps y monitoreo de cobertura», que es lo que
            hace Search Console: cuando aparezca la segunda herramienta, esa
            frase pasaría a nombrar sólo la mitad de lo que hay adentro.
          */}
          <p className="text-muted-foreground text-sm text-pretty">{t('login.tagline')}</p>
        </div>

        <form onSubmit={submit} className="flex flex-col gap-4" noValidate>
          {/*
            Enfocable para poder recibir el foco al llegar. El tono es el mismo
            que el de los dos campos que marca: un aviso ámbar arriba de dos
            campos en rojo serían dos familias para un solo rechazo.
          */}
          {failed ? (
            <Alert
              ref={alertRef}
              tabIndex={-1}
              variant="critical"
              className="focus-visible:ring-ring/50 focus-visible:ring-3 focus-visible:outline-none"
            >
              <CircleAlert />
              <AlertTitle>{t('login.failed')}</AlertTitle>
              <AlertDescription>{faultText(errors.form)}</AlertDescription>
            </Alert>
          ) : null}

          <FieldGroup className="gap-4">
            <Field>
              <FieldLabel htmlFor="email">{t('login.email')}</FieldLabel>
              <Input
                id="email"
                name="email"
                type="email"
                inputMode="email"
                autoComplete="username"
                autoFocus
                value={form.data.email}
                onChange={(event) => form.setData('email', event.target.value)}
                // Los dos campos quedan marcados cuando el rechazo es de los
                // dos juntos: señalar uno solo acusa al que puede estar bien.
                aria-invalid={failed ? true : undefined}
                {...fieldErrorProps('error-email', faultText(errors.email))}
              />
              <FieldError id="error-email" message={faultText(errors.email)} />
            </Field>

            <Field>
              <FieldLabel htmlFor="password">{t('login.password')}</FieldLabel>
              {/* Sin bloqueo de pegado: es lo que hace usable un gestor de contraseñas. */}
              <Input
                id="password"
                name="password"
                type="password"
                autoComplete="current-password"
                value={form.data.password}
                onChange={(event) => form.setData('password', event.target.value)}
                aria-invalid={failed ? true : undefined}
                {...fieldErrorProps('error-password', faultText(errors.password))}
              />
              <FieldError id="error-password" message={faultText(errors.password)} />
            </Field>
          </FieldGroup>

          <Button type="submit" className="w-full" disabled={form.processing}>
            {form.processing ? t('login.submitting') : t('login.submit')}
          </Button>
        </form>
      </div>
    </div>
  )
}
