/**
 * Sign-in.
 *
 * Two methods, because they suit different situations. A password is faster
 * for someone who uses PIG daily and has it in a manager; a magic link needs
 * no credential at all and is the better answer for someone signing in once
 * from a phone. Neither is stored by PIG — both are handled entirely by the
 * identity provider, and PIG only ever sees the resulting token.
 *
 * Password is the default tab because the alternative — defaulting to a link
 * and making daily users switch every time — is the more annoying of the two
 * mistakes.
 */
import { useState } from 'react';
import { Mail } from 'lucide-react';
import { getSupabase, type PublicConfig } from '@/lib/api';
import { Button, Input, Label } from '@/components/ui';
import { FormField } from '@/components/ui/form-field';
import { AuthShell } from '@/components/AuthShell';
import { usePageTitle } from '@/lib/title';

type Method = 'password' | 'link';

export function SignIn({
  config,
  onCreateAccount,
}: {
  config: PublicConfig;
  onCreateAccount: () => void;
}) {
  usePageTitle('Sign in');
  const [method, setMethod] = useState<Method>('password');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [status, setStatus] = useState<'idle' | 'busy' | 'sent' | 'error'>('idle');
  const [message, setMessage] = useState('');

  async function submit(event: React.FormEvent) {
    event.preventDefault();
    const supabase = getSupabase();
    if (!supabase) {
      setStatus('error');
      setMessage('Authentication is not configured on this deployment.');
      return;
    }

    setStatus('busy');
    setMessage('');

    if (method === 'password') {
      const { error } = await supabase.auth.signInWithPassword({ email, password });
      if (error) {
        setStatus('error');
        // Supabase deliberately returns the same message for a wrong password
        // and an unknown address, which is correct — distinguishing them tells
        // an attacker which addresses are registered.
        setMessage(error.message);
        return;
      }
      // The auth state listener in App.tsx picks this up and re-fetches; no
      // navigation is needed here.
      setStatus('idle');
      return;
    }

    const { error } = await supabase.auth.signInWithOtp({
      email,
      options: { emailRedirectTo: window.location.origin },
    });
    if (error) {
      setStatus('error');
      setMessage(error.message);
      return;
    }
    setStatus('sent');
  }

  return (
    <AuthShell>
      <div className="auth-panel rounded-2xl border border-border/80 bg-surface/90 p-5 shadow-2xl backdrop-blur-xl sm:p-7 lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0 lg:shadow-none lg:backdrop-blur-none">
        {status === 'sent' ? (
          <div className="flex flex-col items-center gap-4 py-4 text-center sm:py-8">
            <span className="flex size-12 items-center justify-center rounded-full border border-border bg-surface-2">
              <Mail className="size-5 text-accent-fg" aria-hidden />
            </span>
            <div className="flex flex-col gap-1">
              <h1 className="text-2xl font-semibold tracking-tight">Check your email</h1>
              <p className="max-w-sm text-sm leading-6 text-muted">
                A sign-in link is on its way to {email}. It expires shortly, so use it soon.
              </p>
            </div>
            <button
              type="button"
              onClick={() => setStatus('idle')}
              className="tap text-sm font-medium text-accent-fg"
            >
              Use a different address
            </button>
          </div>
        ) : (
          <>
            <div className="flex flex-col gap-2">
              <Label>Private workspace</Label>
              <h1 className="text-3xl font-medium tracking-[-0.035em] sm:text-4xl">
                Sign in to PIG
              </h1>
              <p className="max-w-md text-sm leading-6 text-muted">
                Authentication stays with the deployment's identity provider. PIG never stores your
                password.
              </p>
            </div>
            <div
              role="tablist"
              aria-label="Sign-in method"
              className="mt-6 flex w-full border-b border-border"
            >
              {(
                [
                  { key: 'password', label: 'Password' },
                  { key: 'link', label: 'Email link' },
                ] as const
              ).map((option) => (
                <button
                  key={option.key}
                  type="button"
                  role="tab"
                  aria-selected={method === option.key}
                  onClick={() => {
                    setMethod(option.key);
                    setStatus('idle');
                    setMessage('');
                  }}
                  className={[
                    'tap relative flex flex-1 items-center justify-center px-3 text-sm font-medium transition-colors duration-1 ease-enter',
                    method === option.key
                      ? 'text-fg after:absolute after:inset-x-3 after:-bottom-px after:h-px after:bg-primary'
                      : 'text-muted hover:text-fg',
                  ].join(' ')}
                >
                  {option.label}
                </button>
              ))}
            </div>

            <form onSubmit={submit} className="mt-5 flex flex-col gap-4">
              <FormField label="Email">
                <Input
                  id="sign-in-email"
                  name="email"
                  type="email"
                  required
                  value={email}
                  onChange={(e) => setEmail(e.target.value)}
                  placeholder="you@company.com"
                  autoComplete="username"
                  autoCapitalize="off"
                  autoCorrect="off"
                  spellCheck={false}
                />
              </FormField>

              {method === 'password' ? (
                <FormField label="Password">
                  <Input
                    id="sign-in-password"
                    name="password"
                    type="password"
                    required
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                    // `current-password` is what lets a password manager
                    // offer to fill, and iOS to offer a saved credential.
                    autoComplete="current-password"
                  />
                </FormField>
              ) : null}

              <Button
                type="submit"
                variant="primary"
                className="mt-1 w-full"
                disabled={status === 'busy'}
              >
                {status === 'busy'
                  ? method === 'password'
                    ? 'Signing in…'
                    : 'Sending…'
                  : method === 'password'
                    ? 'Sign in'
                    : 'Email me a sign-in link'}
              </Button>

              {status === 'error' ? (
                <p className="text-sm text-danger" role="alert">
                  {message}
                </p>
              ) : null}

              {config.canSelfRegister ? (
                <div className="mt-1 border-t border-border pt-4">
                  <p className="text-sm leading-6 text-muted">
                    Have a PIG invite code but no account? Registration remains closed on the shared
                    identity provider.
                  </p>
                  <button
                    type="button"
                    onClick={onCreateAccount}
                    className="tap -ml-2 inline-flex items-center px-2 text-sm font-medium text-accent-fg"
                  >
                    Create an account
                  </button>
                </div>
              ) : config.inviteRequired ? (
                <p className="pt-1 text-center text-xs text-muted">
                  This workspace is invite-only. Ask an administrator to provision access; this
                  screen never opens self-registration.
                </p>
              ) : null}
            </form>
          </>
        )}
      </div>
    </AuthShell>
  );
}
