import { useState, useCallback } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner';
import { Fingerprint, Loader2, Trash2, Cloud, ShieldOff } from 'lucide-react';
import api, { getErrorMessage } from '@/lib/api';
import { Card, CardContent } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Switch } from '@/components/ui/switch';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from '@/components/ui/dialog';
import { Separator } from '@/components/ui/separator';
import { useConfirmAction } from '@/hooks/useConfirmAction';
import { useAuth } from '@/hooks/useAuth';
import type { PasskeyCredential } from '@/types';

function formatRelativeTime(dateStr: string | null): string {
  if (!dateStr) return 'Never';
  const date = new Date(dateStr);
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffMins = Math.floor(diffMs / 60000);
  if (diffMins < 1) return 'Just now';
  if (diffMins < 60) return `${diffMins}m ago`;
  const diffHours = Math.floor(diffMins / 60);
  if (diffHours < 24) return `${diffHours}h ago`;
  const diffDays = Math.floor(diffHours / 24);
  if (diffDays < 30) return `${diffDays}d ago`;
  return date.toLocaleDateString();
}

function formatDate(dateStr: string | null): string {
  if (!dateStr) return '';
  return new Date(dateStr).toLocaleDateString(undefined, {
    day: 'numeric', month: 'short', year: 'numeric',
  });
}

function detectDeviceName(): string {
  const ua = navigator.userAgent;
  let browser = 'Browser';
  if (ua.includes('Chrome') && !ua.includes('Edg')) browser = 'Chrome';
  else if (ua.includes('Safari') && !ua.includes('Chrome')) browser = 'Safari';
  else if (ua.includes('Firefox')) browser = 'Firefox';
  else if (ua.includes('Edg')) browser = 'Edge';

  let os = '';
  if (ua.includes('Mac')) os = 'macOS';
  else if (ua.includes('Windows')) os = 'Windows';
  else if (ua.includes('Linux')) os = 'Linux';
  else if (ua.includes('iPhone') || ua.includes('iPad')) os = 'iOS';
  else if (ua.includes('Android')) os = 'Android';

  return os ? `${os} \u2014 ${browser}` : browser;
}

interface DeleteConfirmProps {
  credential: PasskeyCredential;
  onDelete: (id: number, password: string) => void;
  isDeleting: boolean;
}

function PasskeyDeleteButton({ credential, onDelete, isDeleting }: DeleteConfirmProps) {
  const [showPasswordDialog, setShowPasswordDialog] = useState(false);
  const [password, setPassword] = useState('');

  const { confirming, handleClick } = useConfirmAction(() => {
    setShowPasswordDialog(true);
  });

  const handleSubmitDelete = () => {
    onDelete(credential.id, password);
    setPassword('');
    setShowPasswordDialog(false);
  };

  return (
    <>
      <Button
        variant="ghost"
        size="icon"
        className="h-7 w-7 text-muted-foreground hover:text-red-400"
        onClick={handleClick}
        disabled={isDeleting}
        aria-label={`Remove passkey ${credential.name}`}
      >
        {confirming ? (
          <span className="text-xs font-medium text-red-400">Sure?</span>
        ) : (
          <Trash2 className="h-3.5 w-3.5" />
        )}
      </Button>

      <Dialog open={showPasswordDialog} onOpenChange={setShowPasswordDialog}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>Remove passkey</DialogTitle>
            <DialogDescription>
              Enter your password to remove "{credential.name}".
            </DialogDescription>
          </DialogHeader>
          <div className="space-y-2">
            <Label htmlFor="delete-passkey-password">Password</Label>
            <Input
              id="delete-passkey-password"
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              onKeyDown={(e) => { if (e.key === 'Enter' && password) handleSubmitDelete(); }}
              autoFocus
            />
          </div>
          <DialogFooter>
            <Button variant="outline" onClick={() => setShowPasswordDialog(false)}>
              Cancel
            </Button>
            <Button
              variant="destructive"
              onClick={handleSubmitDelete}
              disabled={!password || isDeleting}
            >
              {isDeleting ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Remove'}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>
    </>
  );
}

export default function PasskeySection() {
  const queryClient = useQueryClient();
  const { passwordlessEnabled, allowPasswordless } = useAuth();

  // Registration state
  const [registerDialogOpen, setRegisterDialogOpen] = useState(false);
  const [ceremonyState, setCeremonyState] = useState<'password' | 'waiting' | 'naming'>('password');
  const [registerPassword, setRegisterPassword] = useState('');
  const [passkeyName, setPasskeyName] = useState('');
  const [pendingCredential, setPendingCredential] = useState<{
    credential: string;
    challenge_token: string;
  } | null>(null);

  // Passwordless enable state
  const [enableDialogOpen, setEnableDialogOpen] = useState(false);
  const [enablePassword, setEnablePassword] = useState('');

  // Passwordless disable state
  const [disableDialogOpen, setDisableDialogOpen] = useState(false);

  const passkeysQuery = useQuery({
    queryKey: ['passkeys'],
    queryFn: async () => {
      const { data } = await api.get<PasskeyCredential[]>('/auth/passkeys');
      return data;
    },
  });

  const registerMutation = useMutation({
    mutationFn: async ({ password }: { password: string }) => {
      const { startRegistration } = await import('@simplewebauthn/browser');

      // Step 1: Get registration options (requires password V-02)
      const { data: beginResp } = await api.post('/auth/passkeys/register/begin', { password });

      // Step 2: Browser WebAuthn ceremony
      setCeremonyState('waiting');
      const credential = await startRegistration(beginResp.options);

      return {
        credential: JSON.stringify(credential),
        challenge_token: beginResp.challenge_token,
      };
    },
    onSuccess: (data) => {
      setPendingCredential(data);
      setPasskeyName(detectDeviceName());
      setCeremonyState('naming');
    },
    onError: (error: unknown) => {
      if (error instanceof Error && error.name === 'NotAllowedError') {
        toast.info('Passkey setup cancelled');
      } else if (error instanceof Error && error.name === 'AbortError') {
        toast.info('Cancelled');
      } else {
        toast.error(getErrorMessage(error, 'Failed to create passkey'));
      }
      setRegisterDialogOpen(false);
      resetRegisterState();
    },
  });

  const completeMutation = useMutation({
    mutationFn: async ({ credential, challenge_token, name }: {
      credential: string; challenge_token: string; name: string;
    }) => {
      const { data } = await api.post('/auth/passkeys/register/complete', {
        credential, challenge_token, name,
      });
      return data;
    },
    onSuccess: () => {
      toast.success('Passkey registered');
      queryClient.invalidateQueries({ queryKey: ['passkeys'] });
      queryClient.invalidateQueries({ queryKey: ['auth'] });
      setRegisterDialogOpen(false);
      resetRegisterState();
    },
    onError: (error: unknown) => {
      toast.error(getErrorMessage(error, 'Failed to save passkey'));
    },
  });

  const deleteMutation = useMutation({
    mutationFn: async ({ id, password }: { id: number; password: string }) => {
      await api.delete(`/auth/passkeys/${id}`, { data: { password } });
    },
    onSuccess: () => {
      toast.success('Passkey removed');
      queryClient.invalidateQueries({ queryKey: ['passkeys'] });
      queryClient.invalidateQueries({ queryKey: ['auth'] });
    },
    onError: (error: unknown) => {
      toast.error(getErrorMessage(error, 'Failed to remove passkey'));
    },
  });

  const enablePasswordlessMutation = useMutation({
    mutationFn: async ({ password }: { password: string }) => {
      const { data } = await api.put('/auth/passkeys/passwordless/enable', { password });
      return data;
    },
    onSuccess: () => {
      toast.success('Passwordless login enabled');
      queryClient.invalidateQueries({ queryKey: ['auth'] });
      queryClient.invalidateQueries({ queryKey: ['passkeys'] });
      setEnableDialogOpen(false);
      setEnablePassword('');
    },
    onError: (error: unknown) => {
      toast.error(getErrorMessage(error, 'Failed to enable passwordless login'));
    },
  });

  const disablePasswordlessMutation = useMutation({
    mutationFn: async () => {
      const { startAuthentication } = await import('@simplewebauthn/browser');
      const { data: beginResp } = await api.post('/auth/passkeys/passwordless/disable/begin', {});
      const credential = await startAuthentication(beginResp.options);
      const { data } = await api.put('/auth/passkeys/passwordless/disable', {
        credential: JSON.stringify(credential),
        challenge_token: beginResp.challenge_token,
      });
      return data;
    },
    onSuccess: () => {
      toast.success('Passwordless login disabled');
      queryClient.invalidateQueries({ queryKey: ['auth'] });
      queryClient.invalidateQueries({ queryKey: ['passkeys'] });
      setDisableDialogOpen(false);
    },
    onError: (error: unknown) => {
      if (error instanceof Error && error.name === 'NotAllowedError') {
        toast.error('Passkey not recognized');
      } else if (error instanceof Error && error.name === 'AbortError') {
        toast.info('Cancelled');
      } else {
        toast.error(getErrorMessage(error, 'Failed to disable passwordless login'));
      }
      setDisableDialogOpen(false);
      // W-03: Invalidate to resync switch state after failed/cancelled ceremony
      queryClient.invalidateQueries({ queryKey: ['auth'] });
    },
  });

  const resetRegisterState = useCallback(() => {
    setCeremonyState('password');
    setRegisterPassword('');
    setPasskeyName('');
    setPendingCredential(null);
  }, []);

  const handleStartRegister = () => {
    resetRegisterState();
    setRegisterDialogOpen(true);
  };

  const handlePasswordSubmit = () => {
    if (!registerPassword) return;
    registerMutation.mutate({ password: registerPassword });
  };

  const handleSaveName = () => {
    if (!pendingCredential || !passkeyName.trim()) return;
    completeMutation.mutate({
      ...pendingCredential,
      name: passkeyName.trim(),
    });
  };

  const handleDelete = (id: number, password: string) => {
    deleteMutation.mutate({ id, password });
  };

  const passkeys = passkeysQuery.data ?? [];
  const hasPasskeys = passkeys.length > 0;

  return (
    <Card>
      <CardContent className="pt-6 space-y-4">
        <div className="flex items-center justify-between">
          <div className="flex items-center gap-2">
            <div className="p-1.5 rounded-md bg-accent/10">
              <Fingerprint className="h-4 w-4 text-accent" />
            </div>
            <div className="space-y-0.5">
              <Label>Passkeys</Label>
              <p className="text-xs text-muted-foreground">
                Sign in with your fingerprint, face, or security key
              </p>
            </div>
          </div>
          {hasPasskeys && (
            <span className="inline-flex items-center rounded-full bg-green-500/10 px-2.5 py-0.5 text-xs font-semibold text-green-400">
              {passkeys.length} registered
            </span>
          )}
        </div>

        {hasPasskeys && (
          <ul className="space-y-1" aria-live="polite">
            {passkeys.map((pk) => (
              <li
                key={pk.id}
                className="flex items-center gap-3 px-3 py-2 rounded-md hover:bg-card-elevated transition-colors duration-150"
              >
                <div className="p-1.5 rounded-md bg-accent/10">
                  <Fingerprint className="h-3.5 w-3.5 text-muted-foreground" />
                </div>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium truncate">{pk.name}</span>
                    {pk.backed_up && (
                      <Cloud className="h-3 w-3 text-muted-foreground shrink-0" aria-label="Synced" />
                    )}
                  </div>
                  <span className="text-xs text-muted-foreground">
                    Added {formatDate(pk.created_at)} · Last used {formatRelativeTime(pk.last_used_at)}
                  </span>
                </div>
                <PasskeyDeleteButton
                  credential={pk}
                  onDelete={handleDelete}
                  isDeleting={deleteMutation.isPending && (deleteMutation.variables as { id: number } | undefined)?.id === pk.id}
                />
              </li>
            ))}
          </ul>
        )}

        <Separator />

        <Button
          variant="outline"
          size="sm"
          className="gap-2"
          onClick={handleStartRegister}
        >
          <Fingerprint className="h-4 w-4" />
          {hasPasskeys ? 'Add another passkey' : 'Add a passkey'}
        </Button>

        {/* Passwordless login section — hidden when admin hasn't enabled the feature */}
        {(allowPasswordless || passwordlessEnabled) && <Separator />}

        {(allowPasswordless || passwordlessEnabled) && (
          <div className="flex items-start justify-between gap-4">
            <div className="space-y-1">
              <div className="flex items-center gap-2">
                <Fingerprint className="h-4 w-4 text-muted-foreground" />
                <Label className="text-sm font-medium">Passwordless Login</Label>
              </div>
              <p className="text-xs text-muted-foreground">
                Skip the password prompt and unlock the app using a passkey only.
              </p>
              {passkeys.length < 2 && !passwordlessEnabled && (
                <p className="text-xs text-amber-400">
                  Requires at least 2 registered passkeys as a fallback.
                </p>
              )}
            </div>
            <Switch
              checked={passwordlessEnabled}
              onCheckedChange={(checked) => {
                if (checked) {
                  setEnablePassword('');
                  setEnableDialogOpen(true);
                } else {
                  setDisableDialogOpen(true);
                  disablePasswordlessMutation.mutate();
                }
              }}
              disabled={(!passwordlessEnabled && passkeys.length < 2) || enablePasswordlessMutation.isPending || disablePasswordlessMutation.isPending}
              aria-label="Toggle passwordless login"
            />
          </div>
        )}

        {/* Enable passwordless dialog */}
        <Dialog open={enableDialogOpen} onOpenChange={(open) => {
          if (!open) { setEnableDialogOpen(false); setEnablePassword(''); }
        }}>
          <DialogContent>
            <DialogHeader>
              <div className="flex items-center gap-3 mb-1">
                <div className="p-2 rounded-lg bg-accent/10">
                  <Fingerprint className="h-5 w-5 text-accent" />
                </div>
                <DialogTitle>Enable Passwordless Login</DialogTitle>
              </div>
              <DialogDescription>
                Confirm your password to enable passkey-only login.
              </DialogDescription>
            </DialogHeader>
            <div className="space-y-2">
              <Label htmlFor="enable-passwordless-password">Password</Label>
              <Input
                id="enable-passwordless-password"
                type="password"
                value={enablePassword}
                onChange={(e) => setEnablePassword(e.target.value)}
                onKeyDown={(e) => {
                  if (e.key === 'Enter' && enablePassword) {
                    enablePasswordlessMutation.mutate({ password: enablePassword });
                  }
                }}
                autoFocus
              />
            </div>
            <DialogFooter>
              <Button variant="outline" onClick={() => { setEnableDialogOpen(false); setEnablePassword(''); }}>
                Cancel
              </Button>
              <Button
                onClick={() => enablePasswordlessMutation.mutate({ password: enablePassword })}
                disabled={!enablePassword || enablePasswordlessMutation.isPending}
              >
                {enablePasswordlessMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Enable'}
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        {/* Disable passwordless dialog */}
        <Dialog open={disableDialogOpen} onOpenChange={(open) => {
          if (!open && !disablePasswordlessMutation.isPending) {
            setDisableDialogOpen(false);
          }
        }}>
          <DialogContent>
            <DialogHeader>
              <div className="flex items-center gap-3 mb-1">
                <div className="p-2 rounded-lg bg-orange-500/10">
                  <ShieldOff className="h-5 w-5 text-orange-400" />
                </div>
                <DialogTitle>Disable Passwordless Login</DialogTitle>
              </div>
              <DialogDescription>
                Verify with your passkey to disable passwordless login.
              </DialogDescription>
            </DialogHeader>
            <div className="flex flex-col items-center gap-4 py-4">
              {disablePasswordlessMutation.isPending ? (
                <>
                  <Loader2 className="h-8 w-8 animate-spin text-accent" />
                  <p className="text-sm text-muted-foreground text-center">
                    Follow your browser's prompt to verify your passkey
                  </p>
                </>
              ) : (
                <p className="text-sm text-muted-foreground text-center">
                  Ready to verify your passkey
                </p>
              )}
            </div>
            <DialogFooter>
              <Button
                variant="outline"
                onClick={() => setDisableDialogOpen(false)}
                disabled={disablePasswordlessMutation.isPending}
              >
                Cancel
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        {/* Registration ceremony dialog */}
        <Dialog
          open={registerDialogOpen}
          onOpenChange={(open) => {
            if (!open) {
              setRegisterDialogOpen(false);
              resetRegisterState();
            }
          }}
        >
          <DialogContent>
            <DialogHeader>
              <div className="flex items-center gap-3 mb-1">
                <div className="p-2 rounded-lg bg-accent/10">
                  <Fingerprint className="h-5 w-5 text-accent" />
                </div>
                <DialogTitle>
                  {ceremonyState === 'password' && 'Add a passkey'}
                  {ceremonyState === 'waiting' && 'Creating passkey'}
                  {ceremonyState === 'naming' && 'Name your passkey'}
                </DialogTitle>
              </div>
            </DialogHeader>

            {ceremonyState === 'password' && (
              <>
                <DialogDescription>
                  Enter your password to add a passkey to your account.
                </DialogDescription>
                <div className="space-y-2">
                  <Label htmlFor="register-passkey-password">Password</Label>
                  <Input
                    id="register-passkey-password"
                    type="password"
                    value={registerPassword}
                    onChange={(e) => setRegisterPassword(e.target.value)}
                    onKeyDown={(e) => { if (e.key === 'Enter' && registerPassword) handlePasswordSubmit(); }}
                    autoFocus
                  />
                </div>
                <DialogFooter>
                  <Button variant="outline" onClick={() => setRegisterDialogOpen(false)}>
                    Cancel
                  </Button>
                  <Button
                    onClick={handlePasswordSubmit}
                    disabled={!registerPassword || registerMutation.isPending}
                  >
                    {registerMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Continue'}
                  </Button>
                </DialogFooter>
              </>
            )}

            {ceremonyState === 'waiting' && (
              <div className="flex flex-col items-center gap-4 py-6">
                <Loader2 className="h-8 w-8 animate-spin text-accent" />
                <p className="text-sm text-muted-foreground text-center">
                  Follow your browser's prompt to create a passkey
                </p>
              </div>
            )}

            {ceremonyState === 'naming' && (
              <>
                <div className="space-y-2">
                  <Label htmlFor="passkey-name">Name</Label>
                  <Input
                    id="passkey-name"
                    value={passkeyName}
                    onChange={(e) => setPasskeyName(e.target.value)}
                    onKeyDown={(e) => { if (e.key === 'Enter' && passkeyName.trim()) handleSaveName(); }}
                    maxLength={100}
                    autoFocus
                  />
                  <p className="text-xs text-muted-foreground">
                    Give this passkey a name to help you identify it later.
                  </p>
                </div>
                <DialogFooter>
                  <Button
                    onClick={handleSaveName}
                    disabled={!passkeyName.trim() || completeMutation.isPending}
                  >
                    {completeMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Save'}
                  </Button>
                </DialogFooter>
              </>
            )}
          </DialogContent>
        </Dialog>
      </CardContent>
    </Card>
  );
}
