import { useState, useEffect } from 'react';
import { invokeWithTracking } from '@/lib/edgeFunctionTracking';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { handleError, handleSuccess, handleNonCriticalError, AppError, getErrorMessage } from '@/lib/errorHandler';
import { logger } from '@/lib/logger';
import { supabase } from '@/lib/supabaseClient';
import { Loader2, Shield, CheckCircle2 } from 'lucide-react';
import { InputOTP, InputOTPGroup, InputOTPSlot } from '@/components/ui/input-otp';
import { TurnstileCaptcha } from '@/components/auth/TurnstileCaptcha';
import { useTheme } from '@/components/theme/ThemeProvider';
import { passwordSchema } from '@/lib/validation';

import { z } from 'zod';

type PasswordFormData = z.infer<typeof passwordSchema>;

interface PasswordUpdateDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  onSuccess: () => void;
}

type Step = 'password' | 'mfa' | 'success';

interface ErrorWithCode {
  code?: string;
  status?: number;
}

function isErrorWithCode(error: unknown): error is Error & ErrorWithCode {
  return error instanceof Error && ('code' in error || 'status' in error);
}

export function PasswordUpdateDialog({ open, onOpenChange, onSuccess }: PasswordUpdateDialogProps) {
  const { theme } = useTheme();
  const [step, setStep] = useState<Step>('password');
  const [loading, setLoading] = useState(false);
  const [nonce, setNonce] = useState<string>('');
  const [newPassword, setNewPassword] = useState<string>('');
  const [hasMFA, setHasMFA] = useState(false);
  const [totpCode, setTotpCode] = useState('');
  const [captchaToken, setCaptchaToken] = useState<string>('');
  const [captchaKey, setCaptchaKey] = useState(0);
  const [userId, setUserId] = useState<string>('');

  const form = useForm<PasswordFormData>({
    resolver: zodResolver(passwordSchema),
    defaultValues: {
      currentPassword: '',
      newPassword: '',
      confirmPassword: ''
    }
  });

  // Check if user has MFA enabled and get user ID
  useEffect(() => {
    if (open) {
      checkMFAStatus();
      supabase.auth.getUser().then(({ data }) => {
        if (data.user) setUserId(data.user.id);
      });
    }
  }, [open]);

  const checkMFAStatus = async () => {
    try {
      const { data, error } = await supabase.auth.mfa.listFactors();
      if (error) throw error;
      
      const hasVerifiedTotp = data?.totp?.some(factor => factor.status === 'verified') || false;
      setHasMFA(hasVerifiedTotp);
    } catch (error: unknown) {
      handleNonCriticalError(error, {
        action: 'Check MFA status',
        userId,
        metadata: { context: 'password_change_dialog' }
      });
    }
  };

  const onSubmit = async (data: PasswordFormData) => {
    if (!captchaToken) {
      handleError(
        new AppError('Please complete the CAPTCHA verification.', 'CAPTCHA_REQUIRED'),
        { 
          action: 'Change password', 
          userId, 
          metadata: { step: 'captcha_validation' } 
        }
      );
      return;
    }

    // Phase 4: AAL2 check for security-critical operations
    if (hasMFA) {
      const { data: { session } } = await supabase.auth.getSession();
      if (session) {
        const jwt = session.access_token;
        const payload = JSON.parse(atob(jwt.split('.')[1]));
        const currentAal = payload.aal || 'aal1';
        
        if (currentAal !== 'aal2') {
          handleError(
            new AppError(
              'Please verify your identity with MFA first',
              'AAL2_REQUIRED'
            ),
            { action: 'Change password', userId, metadata: { step: 'aal2_check' } }
          );
          sessionStorage.setItem('mfa_step_up_required', 'true');
          sessionStorage.setItem('mfa_intended_path', '/settings?tab=security');
          window.location.href = '/auth';
          return;
        }
      }
    }

    setLoading(true);
    try {
      // Step 1: Reauthenticate with current password to get a nonce
      const { error: signInError } = await supabase.auth.signInWithPassword({
        email: (await supabase.auth.getUser()).data.user?.email || '',
        password: data.currentPassword,
        options: {
          captchaToken
        }
      });
      
      if (signInError) {
        // Reset CAPTCHA on authentication failure
        setCaptchaToken('');
        setCaptchaKey(prev => prev + 1);
        
        throw signInError;
      }

      // Step 2: Generate nonce for secure password update
      const { data: sessionData } = await supabase.auth.getSession();
      
      if (!sessionData.session) throw new Error('No active session');

      const generatedNonce = sessionData.session.access_token.substring(0, 32);
      setNonce(generatedNonce);
      setNewPassword(data.newPassword);

      // If user has MFA, require TOTP verification
      if (hasMFA) {
        setStep('mfa');
      } else {
        // No MFA, proceed with password update
        await updatePasswordWithNonce(data.newPassword, generatedNonce);
      }
    } catch (error: unknown) {
      const errorMessage = getErrorMessage(error);
      const errorStatus = isErrorWithCode(error) ? error.status : undefined;
      
      if (errorMessage?.includes('rate limit') || errorStatus === 429) {
        handleError(
          new AppError(
            'Please wait a few minutes before trying again.',
            'RATE_LIMIT',
            'Too many password change attempts'
          ),
          { action: 'Change password', userId, metadata: { step: 'authentication' } }
        );
      } else if (errorMessage?.includes('Invalid login credentials')) {
        handleError(
          new AppError(
            'The password you entered is incorrect.',
            'INVALID_PASSWORD',
            'Incorrect current password'
          ),
          { action: 'Verify password', userId }
        );
      } else {
        handleError(error, { 
          action: 'Change password', 
          userId,
          metadata: { step: 'authentication' }
        });
      }
    } finally {
      setLoading(false);
    }
  };

  const verifyMFAAndUpdate = async () => {
    if (totpCode.length !== 6) {
      handleError(
        new AppError('Please enter a valid 6-digit code', 'INVALID_MFA_CODE'),
        { action: 'Verify MFA', userId, metadata: { step: 'mfa_verification' } }
      );
      return;
    }

    setLoading(true);
    try {
      // Get the factor ID first
      const factorId = (await supabase.auth.mfa.listFactors()).data?.totp?.[0]?.id || '';
      
      if (!factorId) {
        throw new Error('No MFA factor found');
      }
      
      // Create challenge
      const { data: challengeData, error: challengeError } = await supabase.auth.mfa.challenge({
        factorId
      });

      if (challengeError) {
        throw challengeError;
      }

      // Verify TOTP code with correct factorId
      const { error: verifyError } = await supabase.auth.mfa.verify({
        factorId,
        challengeId: challengeData.id,
        code: totpCode
      });

      if (verifyError) {
        throw verifyError;
      }

      // TOTP verified, now update password
      await updatePasswordWithNonce(newPassword, nonce);
    } catch (error: unknown) {
      handleError(
        new AppError(
          getErrorMessage(error) || 'Invalid authentication code',
          'MFA_VERIFICATION_FAILED',
          'TOTP code verification failed'
        ),
        { action: 'Verify MFA', userId, metadata: { step: 'mfa_verification' } }
      );
    } finally {
      setLoading(false);
    }
  };

  const updatePasswordWithNonce = async (password: string, nonceValue: string) => {
    try {
      // Step 2: Update password
      const { error: updateError } = await supabase.auth.updateUser({
        password
      });

      if (updateError) throw updateError;

      // Step 3: Log audit trail
      const { data: { user } } = await supabase.auth.getUser();
      if (user) {
        await supabase.from('admin_audit_log').insert({
          admin_user_id: user.id,
          target_user_id: user.id,
          action: 'password_changed',
          details: {
            timestamp: new Date().toISOString(),
            method: hasMFA ? 'password_with_mfa' : 'password_only',
            user_agent: navigator.userAgent
          }
        });

        // Step 4: Send security notification
        try {
          await invokeWithTracking(
            'trigger-notification',
            {
              workflowId: 'security-alert',
              subscriberId: user.id,
              payload: {
                alert_type: 'password_changed',
                timestamp: new Date().toISOString(),
                device: navigator.userAgent.split(' ')[0]
              }
            },
            user.id
          );
        } catch (notifError) {
          handleNonCriticalError(notifError, {
            action: 'Send password change notification',
            userId: user!.id,
            metadata: { context: 'post_password_change' }
          });
          // Don't fail the password update if notification fails
        }
      }

      setStep('success');
      form.reset();
      
      // Auto-close after 2 seconds
      setTimeout(() => {
        onOpenChange(false);
        onSuccess();
        setStep('password');
        setTotpCode('');
      }, 2000);
    } catch (error: unknown) {
      throw error;
    }
  };

  const handleClose = () => {
    if (!loading) {
      onOpenChange(false);
      setStep('password');
      form.reset();
      setTotpCode('');
      setCaptchaToken('');
      setCaptchaKey(prev => prev + 1);
    }
  };

  return (
    <Dialog open={open} onOpenChange={handleClose}>
      <DialogContent className="sm:max-w-md">
        {step === 'password' && (
          <>
            <DialogHeader>
              <DialogTitle>Change Password</DialogTitle>
              <DialogDescription>
                Enter your current password and choose a new one. {hasMFA && 'You will need to verify with your authenticator app.'}
              </DialogDescription>
            </DialogHeader>

            <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
              <div className="space-y-2">
                <Label htmlFor="currentPassword">Current Password</Label>
                <Input
                  id="currentPassword"
                  type="password"
                  {...form.register('currentPassword')}
                  placeholder="Enter your current password"
                  disabled={loading}
                />
                {form.formState.errors.currentPassword && (
                  <p className="text-sm text-destructive">
                    {form.formState.errors.currentPassword.message}
                  </p>
                )}
              </div>

              <div className="space-y-2">
                <Label htmlFor="newPassword">New Password</Label>
                <Input
                  id="newPassword"
                  type="password"
                  {...form.register('newPassword')}
                  placeholder="Enter your new password"
                  disabled={loading}
                />
                <p className="text-xs text-muted-foreground">
                  Must be 8+ characters with uppercase, lowercase, number, and special character
                </p>
                {form.formState.errors.newPassword && (
                  <p className="text-sm text-destructive">
                    {form.formState.errors.newPassword.message}
                  </p>
                )}
              </div>

              <div className="space-y-2">
                <Label htmlFor="confirmPassword">Confirm New Password</Label>
                <Input
                  id="confirmPassword"
                  type="password"
                  {...form.register('confirmPassword')}
                  placeholder="Confirm your new password"
                  disabled={loading}
                />
                {form.formState.errors.confirmPassword && (
                  <p className="text-sm text-destructive">
                    {form.formState.errors.confirmPassword.message}
                  </p>
                )}
              </div>

              <div className="space-y-2">
                <TurnstileCaptcha
                  key={captchaKey}
                  onSuccess={setCaptchaToken}
                  onError={() => setCaptchaToken('')}
                  onExpire={() => setCaptchaToken('')}
                  siteKey={import.meta.env.VITE_TURNSTILE_SITE_KEY}
                  theme={theme === 'dark' ? 'dark' : 'light'}
                  size="normal"
                />
              </div>

              <DialogFooter>
                <Button type="button" variant="outline" onClick={handleClose} disabled={loading}>
                  Cancel
                </Button>
                <Button type="submit" disabled={loading || !captchaToken}>
                  {loading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
                  {hasMFA ? 'Continue' : 'Update Password'}
                </Button>
              </DialogFooter>
            </form>
          </>
        )}

        {step === 'mfa' && (
          <>
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2">
                <Shield className="h-5 w-5" />
                Verify Your Identity
              </DialogTitle>
              <DialogDescription>
                Enter the 6-digit code from your authenticator app to complete the password change.
              </DialogDescription>
            </DialogHeader>

            <div className="space-y-4 py-4">
              <div className="flex flex-col items-center gap-4">
                <Label htmlFor="totp-code">Code from Authenticator App</Label>
                <InputOTP
                  maxLength={6}
                  value={totpCode}
                  onChange={setTotpCode}
                  disabled={loading}
                >
                  <InputOTPGroup>
                    <InputOTPSlot index={0} />
                    <InputOTPSlot index={1} />
                    <InputOTPSlot index={2} />
                    <InputOTPSlot index={3} />
                    <InputOTPSlot index={4} />
                    <InputOTPSlot index={5} />
                  </InputOTPGroup>
                </InputOTP>
              </div>
            </div>

            <DialogFooter>
              <Button
                variant="outline"
                onClick={() => {
                  setStep('password');
                  setTotpCode('');
                }}
                disabled={loading}
              >
                Back
              </Button>
              <Button onClick={verifyMFAAndUpdate} loading={loading} loadingText="Verifying..." disabled={totpCode.length !== 6}>
                Verify & Update
              </Button>
            </DialogFooter>
          </>
        )}

        {step === 'success' && (
          <>
            <DialogHeader>
              <DialogTitle className="flex items-center gap-2 text-green-600">
                <CheckCircle2 className="h-5 w-5" />
                Password Updated
              </DialogTitle>
              <DialogDescription>
                Your password has been successfully changed. A security notification has been sent to your email.
              </DialogDescription>
            </DialogHeader>
          </>
        )}
      </DialogContent>
    </Dialog>
  );
}
