import { useState, useEffect } from 'react';
import { Link, useNavigate } from 'react-router-dom';
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 {
  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;
}

export default function LoginPage() {
  const navigate = useNavigate();
  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' : '/');

  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 {
      navigate(destFor(user), { replace: true });
    }
  };

  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 {
        navigate(destFor(pendingUser), { replace: true });
      }
    } 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);
    navigate(destFor(pendingUser), { replace: true });
  };

  return (
    <div className="min-h-screen bg-background flex items-center justify-center p-4">

      <div className="w-full max-w-sm space-y-6">

        {/* Logo / Brand */}
        <div className="flex justify-center">
          <img
            src="/img/logo.png"
            alt="BillTracker"
            className="h-auto w-[82%] max-w-[12rem] object-contain drop-shadow-[0_1px_2px_rgba(0,0,0,0.45)]"
          />
        </div>

        {/* TOTP step — shown after password is accepted */}
        {totpChallenge && (
          <div className="surface-elevated p-8 space-y-5">
            <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>

            <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 p-8 flex items-center justify-center min-h-[120px]">
            <span className="text-sm text-muted-foreground">Loading…</span>
          </div>
        ) : (
        <div className="surface-elevated p-8 space-y-6">

          <div>
            <h1 className="text-lg font-semibold">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>

      {/* Change Password Dialog */}
      <Dialog open={showChangePw}>
        <DialogContent onInteractOutside={e => e.preventDefault()}>
          <DialogHeader>
            <DialogTitle>Change your password</DialogTitle>
            <DialogDescription>
              You must set a new password before continuing.
            </DialogDescription>
          </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>
            <DialogTitle>Privacy notice</DialogTitle>
            <DialogDescription>
              Please read before continuing.
            </DialogDescription>
          </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-lg 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">
                  <span className="text-emerald-400">✓</span>
                  <span>Reset your password if locked out</span>
                </li>
                <li className="flex gap-2">
                  <span className="text-red-400">✗</span>
                  <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>
  );
}
