'use client'

import { useState, type FormEvent } from 'react'

import { useI18n } from '@/components/providers/i18n-provider'
import { Button, Field, Input, Notice } from '@/components/ui/controls'
import { ApiClientError, api, failureMessage, fieldErrorMessage } from '@/lib/api/client'

export interface DemoAccount {
  email: string
  name: string
  nameAr: string
  roleKey: string
}

export function LoginForm({
  next,
  demoAccounts,
  demoPassword,
}: {
  next?: string
  demoAccounts: DemoAccount[]
  demoPassword: string | null
}) {
  const { t, locale } = useI18n()

  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [error, setError] = useState<string | null>(null)
  const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({})
  const [submitting, setSubmitting] = useState(false)

  /**
   * Sign in with a given pair.
   *
   * Takes its credentials as arguments rather than reading component state, because the
   * demo cards sign in with values they have just set — and state set in the same tick is
   * not yet readable. Passing them straight through removes the race rather than papering
   * over it with a timeout.
   */
  const signIn = async (withEmail: string, withPassword: string) => {
    if (submitting) return
    setSubmitting(true)
    setError(null)
    setFieldErrors({})

    try {
      await api.post('/api/auth/login', { email: withEmail, password: withPassword })
      // A full navigation rather than a client push: the session cookie has just been
      // set, and the server tree must be rebuilt with the new identity and locale.
      window.location.assign(next && next.startsWith('/') ? next : '/dashboard')
    } catch (caught) {
      if (caught instanceof ApiClientError) {
        setError(failureMessage(caught.failure, locale))
        if (caught.failure.details) setFieldErrors(caught.failure.details)
      } else {
        setError(t('common.serverError'))
      }
      setSubmitting(false)
    }
  }

  const onSubmit = (event: FormEvent) => {
    event.preventDefault()
    void signIn(email, password)
  }

  /**
   * Pick a role and go.
   *
   * With the seeded password available this signs in directly — the point of the roster is
   * to move between roles, and a card that only filled a field made that two steps. Without
   * one it fills the address and hands over the field the reader must still complete.
   */
  const applyAccount = (account: DemoAccount) => {
    setEmail(account.email)
    setError(null)
    setFieldErrors({})
    if (demoPassword) {
      setPassword(demoPassword)
      void signIn(account.email, demoPassword)
      return
    }
    document.getElementById('password')?.focus()
  }

  return (
    <div className="space-y-6">
      <form onSubmit={onSubmit} className="space-y-4" noValidate>
        {error ? <Notice tone="danger">{error}</Notice> : null}

        <Field label={t('auth.email')} htmlFor="email" error={fieldErrorMessage(fieldErrors.email, t)}>
          <Input
            id="email"
            name="email"
            type="email"
            autoComplete="username"
            required
            dir="ltr"
            value={email}
            invalid={Boolean(fieldErrors.email)}
            onChange={(event) => setEmail(event.target.value)}
            placeholder={t('auth.emailPlaceholder')}
          />
        </Field>

        <Field
          label={t('auth.password')}
          htmlFor="password"
          error={fieldErrorMessage(fieldErrors.password, t)}
        >
          <Input
            id="password"
            name="password"
            type="password"
            autoComplete="current-password"
            required
            dir="ltr"
            value={password}
            invalid={Boolean(fieldErrors.password)}
            onChange={(event) => setPassword(event.target.value)}
            placeholder={t('auth.passwordPlaceholder')}
          />
        </Field>

        <Button type="submit" size="lg" loading={submitting} className="w-full">
          {submitting ? t('auth.submitting') : t('auth.submit')}
        </Button>
      </form>

      {demoAccounts.length > 0 ? (
        <div className="border-t border-border pt-5">
          <div className="flex flex-wrap items-baseline justify-between gap-2">
            <h2 className="text-xs font-semibold uppercase tracking-[0.14em] text-text-faint">
              {t('auth.demoAccounts')}
            </h2>
            {demoPassword ? (
              <span className="flex items-center gap-2 text-[11px]">
                <span className="text-text-muted">{t('auth.demoOneClick')}</span>
                <span className="font-mono text-text-muted">{demoPassword}</span>
              </span>
            ) : (
              // Outside development the seeded password is deliberately withheld. Saying so
              // here is the difference between a button that half-works and one whose
              // behaviour was explained before it was pressed.
              <span className="text-[11px] text-text-muted">{t('auth.demoPasswordHidden')}</span>
            )}
          </div>

          <ul className="mt-3 grid gap-1.5 sm:grid-cols-2">
            {demoAccounts.map((account) => (
              <li key={account.email}>
                <button
                  type="button"
                  onClick={() => applyAccount(account)}
                  disabled={submitting}
                  aria-busy={submitting && email === account.email}
                  className="w-full rounded-lg border border-border bg-surface-2/60 px-3 py-2 text-start transition-colors hover:border-brand/40 hover:bg-brand/8 disabled:opacity-60"
                >
                  <span className="block truncate text-xs font-medium text-text">
                    {locale === 'ar' ? account.nameAr : account.name}
                  </span>
                  {/* The role, under the name: with one person holding every account, the
                      role is what tells these cards apart. */}
                  <span className="mt-0.5 block truncate text-[11px] text-brand">
                    {t(`role.${account.roleKey}`)}
                  </span>
                  <span className="mt-0.5 block truncate font-mono text-[11px] text-text-faint">
                    {submitting && email === account.email ? t('auth.submitting') : account.email}
                  </span>
                </button>
              </li>
            ))}
          </ul>

          <p className="mt-3 text-[11px] leading-relaxed text-text-faint">
            {t('auth.demoAccountsNote')}
          </p>
        </div>
      ) : null}
    </div>
  )
}
