import { useState, useEffect, type ComponentType, type ReactNode } from 'react';
import { Link, useNavigate, useLocation } from 'react-router-dom';
import { Gauge, KeyRound, LockKeyhole, ShieldCheck } from 'lucide-react';
import { toast } from 'sonner';
import { api } from '@/api';
import { errMessage } from '@/lib/utils';
import { useAuth, type User } from '@/hooks/useAuth';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { APP_VERSION } from '@/lib/version';
import { BRAND } from '@/lib/brand';
import { BrandGlyph, BrandMark } from '@/components/brand/Brand';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from '@/components/ui/dialog';

const BUILD_LINK_URL = 'https://dream.scheller.ltd/null/BillTracker';

interface AuthModeInfo {
  auth_mode?: string;
  local_enabled?: boolean;
  oidc_enabled?: boolean;
  oidc_login_url?: string;
  oidc_provider_name?: string;
}

const LANDING_ROUTES: Record<string, string> = {
  tracker: '/',
  calendar: '/calendar',
  summary: '/summary',
  spending: '/spending',
};

function TrustItem({
  icon: Icon,
  title,
  children,
}: {
  icon: ComponentType<{ className?: string }>;
  title: string;
  children: ReactNode;
}) {
  return (
    <div className="flex gap-3 rounded-xl border border-border/65 bg-card/50 p-3 shadow-sm shadow-black/5 backdrop-blur-sm">
      <span className="mt-0.5 grid h-8 w-8 shrink-0 place-items-center rounded-lg border border-primary/20 bg-primary/10 text-primary">
        <Icon className="h-4 w-4" aria-hidden="true" />
      </span>
      <div className="min-w-0">
        <p className="text-sm font-semibold text-foreground">{title}</p>
        <p className="mt-0.5 text-xs leading-5 text-muted-foreground">{children}</p>
      </div>
    </div>
  );
}

export default function LoginPage() {
  const navigate = useNavigate();
  const location = useLocation();
  const { setUser, refresh } = useAuth();

  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState('');
  const [authMode, setAuthMode] = useState<AuthModeInfo | null>(null); // null = still loading

  const [pendingUser, setPendingUser] = useState<User | null>(null);
  const [showChangePw, setShowChangePw] = useState(false);
  const [showPrivacy, setShowPrivacy] = useState(false);

  // TOTP challenge state
  const [totpChallenge, setTotpChallenge] = useState<string | null>(null); // challenge_token string
  const [totpCode, setTotpCode] = useState('');
  const [totpError, setTotpError] = useState('');
  const [totpLoading, setTotpLoading] = useState(false);
  const [useRecovery, setUseRecovery] = useState(false);

  const [newPw, setNewPw] = useState('');
  const [confirmPw, setConfirmPw] = useState('');
  const [pwLoading, setPwLoading] = useState(false);

  const destFor = (user?: User | null) => (user?.is_default_admin ? '/admin' : '/');

  // Where to send the user after signing in. Precedence: admin console →
  // explicit deep-link they were bounced from → their default landing page → /.
  const resolveDest = async (user?: User | null): Promise<string> => {
    if (user?.is_default_admin) return '/admin';
    const from = (location.state as { from?: { pathname?: string } } | null)?.from?.pathname;
    if (from && from !== '/login') return from;
    try {
      const s = (await api.settings()) as Record<string, unknown>;
      const landing =
        typeof s.default_landing_page === 'string'
          ? LANDING_ROUTES[s.default_landing_page]
          : undefined;
      return landing || '/';
    } catch {
      return '/'; // never block login on a settings-fetch failure
    }
  };
  const navigateAfterAuth = async (user?: User | null) => {
    navigate(await resolveDest(user), { replace: true });
  };

  useEffect(() => {
    api
      .authMode()
      .then((raw) => {
        const d = raw as AuthModeInfo;
        setAuthMode(d);
        if (d.auth_mode === 'single') navigate('/', { replace: true });
      })
      .catch((err) => console.error('[LoginPage] authMode check failed', err));

    api
      .me()
      .then((raw) => {
        const d = raw as { user?: User };
        if (d.user) navigate(destFor(d.user), { replace: true });
      })
      .catch((err) => console.error('[LoginPage] session check failed', err));
  }, []); // eslint-disable-line

  const handlePostLogin = (user: User) => {
    setUser(user);
    if (user.must_change_password) {
      setPendingUser(user);
      setShowChangePw(true);
      setShowPrivacy(false);
    } else if (user.first_login) {
      setPendingUser(user);
      setShowPrivacy(true);
      setShowChangePw(false);
    } else {
      void navigateAfterAuth(user);
    }
  };

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setError('');
    setLoading(true);
    try {
      const data = await api.login({ username, password });
      if (data.requires_totp) {
        setTotpChallenge(data.challenge_token ?? null);
        setTotpCode('');
        setTotpError('');
        setUseRecovery(false);
        return;
      }
      handlePostLogin(data.user!);
    } catch (err) {
      setError(errMessage(err, 'Login failed.'));
    } finally {
      setLoading(false);
    }
  };

  const handleTotpSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setTotpError('');
    setTotpLoading(true);
    try {
      const payload: { challenge_token: string | null; recovery_code?: string; code?: string } = {
        challenge_token: totpChallenge,
      };
      if (useRecovery) payload.recovery_code = totpCode;
      else payload.code = totpCode;
      const data = await api.totpChallenge(payload);
      handlePostLogin(data.user!);
    } catch (err) {
      setTotpError(errMessage(err, 'Invalid code.'));
      setTotpCode('');
    } finally {
      setTotpLoading(false);
    }
  };

  const localEnabled = authMode?.local_enabled !== false;
  const oidcEnabled = !!authMode?.oidc_enabled && !!authMode?.oidc_login_url;
  const providerName = authMode?.oidc_provider_name || 'authentik';
  const isAuthentikProvider = providerName.toLowerCase().includes('authentik');

  const handleChangePassword = async (e: React.FormEvent) => {
    e.preventDefault();

    if (newPw !== confirmPw) {
      toast.error('Passwords do not match.');
      return;
    }

    if (newPw.length < 8) {
      toast.error('Password must be at least 8 characters.');
      return;
    }

    setPwLoading(true);
    try {
      await api.changePassword({ new_password: newPw });
      toast.success('Password updated.');
      setShowChangePw(false);
      refresh();

      if (pendingUser?.first_login) {
        setShowPrivacy(true);
      } else {
        void navigateAfterAuth(pendingUser);
      }
    } catch (err) {
      toast.error(errMessage(err, 'Failed to change password.'));
    } finally {
      setPwLoading(false);
    }
  };

  const handleAcknowledgePrivacy = async () => {
    try {
      await api.acknowledgePrivacy();
    } catch {
      /* ignore */
    }

    refresh();
    setShowPrivacy(false);
    void navigateAfterAuth(pendingUser);
  };

  return (
    <div className="min-h-screen bg-[radial-gradient(circle_at_20%_0%,oklch(var(--primary)/0.16),transparent_30rem),radial-gradient(circle_at_84%_82%,oklch(var(--accent)/0.12),transparent_26rem),linear-gradient(180deg,oklch(var(--background)),oklch(var(--muted)/0.18))] p-4 sm:p-6 lg:p-8">
      <div className="mx-auto grid min-h-[calc(100vh-2rem)] w-full max-w-6xl items-center gap-8 sm:min-h-[calc(100vh-3rem)] lg:min-h-[calc(100vh-4rem)] lg:grid-cols-[minmax(0,1fr)_minmax(22rem,25rem)]">
        <section className="hidden lg:block">
          <div className="max-w-xl space-y-8">
            <div>
              <BrandMark className="h-auto w-[18rem] drop-shadow-[0_18px_44px_rgba(0,0,0,0.22)]" />
              <p className="mt-5 max-w-md text-lg leading-8 text-muted-foreground">
                {BRAND.tagline} Built for fast bill scanning, clear household decisions, and private
                defaults.
              </p>
            </div>

            <div className="grid max-w-lg gap-3">
              <TrustItem icon={ShieldCheck} title="Private by design">
                Admins can manage access, but they cannot inspect personal bills or spending
                history.
              </TrustItem>
              <TrustItem icon={Gauge} title="Fast daily control">
                Dense tracker views, tabular money, and calm status cues stay front and center.
              </TrustItem>
              <TrustItem icon={LockKeyhole} title="Ready for stronger sign-in">
                Local login, SSO, and two-factor flows share one clean entry point.
              </TrustItem>
            </div>
          </div>
        </section>

        <div className="mx-auto w-full max-w-sm space-y-6">
          {/* Logo / Brand */}
          <div className="flex flex-col items-center text-center lg:hidden">
            <BrandMark className="h-auto w-[78%] max-w-[12rem] drop-shadow-[0_10px_28px_rgba(0,0,0,0.18)]" />
            <p className="mt-3 max-w-xs text-sm leading-6 text-muted-foreground">{BRAND.tagline}</p>
          </div>
          {/* TOTP step — shown after password is accepted */}
          {totpChallenge && (
            <div className="surface-elevated p-8 space-y-5">
              <div className="flex gap-3">
                <BrandGlyph name="security" className="h-11 w-11 rounded-2xl" />
                <div>
                  <h1 className="text-lg font-semibold">Two-factor authentication</h1>
                  <p className="text-sm text-muted-foreground mt-1">
                    {useRecovery
                      ? 'Enter one of your recovery codes.'
                      : 'Enter the 6-digit code from your authenticator app.'}
                  </p>
                </div>
              </div>

              <form onSubmit={handleTotpSubmit} className="space-y-4">
                <div className="space-y-1.5">
                  <Label htmlFor="totp-code">
                    {useRecovery ? 'Recovery code' : 'Authenticator code'}
                  </Label>
                  <Input
                    id="totp-code"
                    value={totpCode}
                    onChange={(e) => setTotpCode(e.target.value)}
                    placeholder={useRecovery ? 'XXXXX-XXXXX' : '000 000'}
                    autoComplete="one-time-code"
                    autoFocus
                    disabled={totpLoading}
                    maxLength={useRecovery ? 11 : 7}
                    className="text-center tracking-widest text-lg font-mono"
                    required
                  />
                </div>

                {totpError && (
                  <div className="text-sm text-destructive bg-destructive/10 border border-destructive/20 rounded-md px-3 py-2">
                    {totpError}
                  </div>
                )}

                <Button type="submit" className="w-full" disabled={totpLoading || !totpCode.trim()}>
                  {totpLoading ? 'Verifying…' : 'Verify'}
                </Button>
              </form>

              <div className="text-center space-y-2">
                <button
                  type="button"
                  className="text-xs text-muted-foreground underline-offset-4 hover:underline hover:text-foreground transition-colors"
                  onClick={() => {
                    setUseRecovery((v) => !v);
                    setTotpCode('');
                    setTotpError('');
                  }}
                >
                  {useRecovery
                    ? 'Use authenticator app instead'
                    : "Can't access your app? Use a recovery code"}
                </button>
                <br />
                <button
                  type="button"
                  className="text-xs text-muted-foreground underline-offset-4 hover:underline hover:text-foreground transition-colors"
                  onClick={() => {
                    setTotpChallenge(null);
                    setTotpCode('');
                    setTotpError('');
                  }}
                >
                  ← Back to sign in
                </button>
              </div>
            </div>
          )}
          {/* Sign-in card — hidden while auth mode resolves or during TOTP step */}
          {!totpChallenge &&
            (authMode === null ? (
              <div className="surface-elevated flex min-h-[120px] items-center justify-center p-8">
                <span className="text-sm text-muted-foreground">Loading…</span>
              </div>
            ) : (
              <div className="surface-elevated space-y-6 p-8">
                <div>
                  <div className="mb-3 inline-flex items-center gap-2 rounded-full border border-primary/20 bg-primary/10 px-3 py-1 text-xs font-semibold text-primary">
                    <KeyRound className="h-3.5 w-3.5" aria-hidden="true" />
                    Secure household access
                  </div>
                  <h1 className="text-xl font-semibold tracking-tight">Sign in</h1>
                  <p className="text-sm text-muted-foreground mt-1">
                    {localEnabled
                      ? 'Enter your credentials to continue.'
                      : `Continue with ${providerName}.`}
                  </p>
                </div>

                {oidcEnabled && (
                  <Button
                    type="button"
                    variant={localEnabled ? 'outline' : 'default'}
                    className="w-full gap-2"
                    onClick={() => {
                      window.location.href = authMode?.oidc_login_url || '';
                    }}
                  >
                    {isAuthentikProvider && (
                      <img
                        src="/img/auth.png"
                        alt=""
                        aria-hidden="true"
                        className="h-5 w-5 object-contain shrink-0"
                        onError={(e) => {
                          (e.target as HTMLImageElement).style.display = 'none';
                        }}
                      />
                    )}
                    Continue with {providerName}
                  </Button>
                )}

                {localEnabled && oidcEnabled && (
                  <div className="flex items-center gap-3 text-xs text-muted-foreground">
                    <div className="h-px flex-1 bg-border" />
                    <span>or</span>
                    <div className="h-px flex-1 bg-border" />
                  </div>
                )}

                {localEnabled && (
                  <form onSubmit={handleLogin} className="space-y-4">
                    <div className="space-y-1.5">
                      <Label htmlFor="username">Username</Label>
                      <Input
                        id="username"
                        autoComplete="username"
                        value={username}
                        onChange={(e) => setUsername(e.target.value)}
                        disabled={loading}
                        required
                      />
                    </div>

                    <div className="space-y-1.5">
                      <Label htmlFor="password">Password</Label>
                      <Input
                        id="password"
                        type="password"
                        autoComplete="current-password"
                        value={password}
                        onChange={(e) => setPassword(e.target.value)}
                        disabled={loading}
                        required
                      />
                    </div>

                    {error && (
                      <div
                        className="text-sm text-destructive bg-destructive/10
                              border border-destructive/20 rounded-md px-3 py-2"
                      >
                        {error}
                      </div>
                    )}

                    <Button type="submit" className="w-full" disabled={loading}>
                      {loading ? 'Signing in…' : 'Sign In'}
                    </Button>
                  </form>
                )}

                <p className="text-center text-xs text-muted-foreground">
                  <a
                    href={BUILD_LINK_URL}
                    target="_blank"
                    rel="noreferrer"
                    className="underline-offset-4 transition-colors hover:text-foreground hover:underline"
                  >
                    Build v{APP_VERSION}
                  </a>
                </p>
                <div className="flex items-center justify-center gap-3 text-xs text-muted-foreground">
                  <Link
                    to="/about"
                    className="underline-offset-4 transition-colors hover:text-foreground hover:underline"
                  >
                    About
                  </Link>
                  <Link
                    to="/release-notes"
                    className="underline-offset-4 transition-colors hover:text-foreground hover:underline"
                  >
                    Release Notes
                  </Link>
                </div>
              </div>
            ))}{' '}
          {/* end !totpChallenge + authMode check */}
        </div>
      </div>

      {/* Change Password Dialog */}
      <Dialog open={showChangePw}>
        <DialogContent onInteractOutside={(e) => e.preventDefault()}>
          <DialogHeader>
            <div className="mb-2 flex items-center gap-3">
              <BrandGlyph name="security" className="h-11 w-11 rounded-2xl" />
              <div>
                <DialogTitle>Change your password</DialogTitle>
                <DialogDescription>Set a new password before continuing.</DialogDescription>
              </div>
            </div>
          </DialogHeader>

          <form onSubmit={handleChangePassword} className="space-y-4 pt-2">
            <div className="space-y-1.5">
              <Label>New password</Label>
              <Input
                type="password"
                value={newPw}
                onChange={(e) => setNewPw(e.target.value)}
                required
              />
            </div>

            <div className="space-y-1.5">
              <Label>Confirm password</Label>
              <Input
                type="password"
                value={confirmPw}
                onChange={(e) => setConfirmPw(e.target.value)}
                required
              />
            </div>

            <DialogFooter>
              <Button type="submit" className="w-full" disabled={pwLoading}>
                {pwLoading ? 'Saving…' : 'Set Password'}
              </Button>
            </DialogFooter>
          </form>
        </DialogContent>
      </Dialog>

      {/* Privacy Dialog */}
      <Dialog open={showPrivacy}>
        <DialogContent onInteractOutside={(e) => e.preventDefault()}>
          <DialogHeader>
            <div className="mb-2 flex items-center gap-3">
              <BrandGlyph name="security" className="h-11 w-11 rounded-2xl" />
              <div>
                <DialogTitle>Privacy notice</DialogTitle>
                <DialogDescription>
                  A quick boundary check before your first session.
                </DialogDescription>
              </div>
            </div>
          </DialogHeader>

          <div className="space-y-3 text-sm text-muted-foreground py-2">
            <p>Your financial data is stored privately and is accessible only to you.</p>

            <div className="rounded-xl bg-muted/50 border border-border p-4 space-y-2">
              <p className="font-medium text-foreground">What your administrator can do:</p>

              <ul className="space-y-1.5">
                <li className="flex gap-2">
                  <ShieldCheck
                    className="mt-0.5 h-4 w-4 shrink-0 text-emerald-500"
                    aria-hidden="true"
                  />
                  <span>Reset your password if locked out</span>
                </li>
                <li className="flex gap-2">
                  <LockKeyhole
                    className="mt-0.5 h-4 w-4 shrink-0 text-rose-500"
                    aria-hidden="true"
                  />
                  <span>Cannot view your financial data</span>
                </li>
              </ul>
            </div>
          </div>

          <DialogFooter>
            <Button className="w-full" onClick={handleAcknowledgePrivacy}>
              I understand — continue
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </div>
  );
}
