import { useState, useEffect } from 'react'
import { useNavigate, useLocation } from 'react-router-dom'
import { Shield, Smartphone, Fingerprint, ShieldCheck, ArrowLeft, AlertCircle } from 'lucide-react'
import { api, getErrorMessage } from '../lib/api'

interface TwoFactorAuthProps {
  username: string
  availableMethods: string[]
  rememberMe: boolean
}

type Method = 'totp' | 'passkey' | 'duo'

export default function TwoFactorAuth() {
  const navigate = useNavigate()
  const location = useLocation()
  const state = location.state as TwoFactorAuthProps

  const [selectedMethod, setSelectedMethod] = useState<Method | null>(null)
  const [totpCode, setTotpCode] = useState('')
  const [useBackupCode, setUseBackupCode] = useState(false)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')
  const [attemptsRemaining, setAttemptsRemaining] = useState<number | null>(null)

  // Redirect if no state
  useEffect(() => {
    if (!state || !state.username || !state.availableMethods) {
      navigate('/login')
    }
  }, [state, navigate])

  if (!state) {
    return null
  }

  const { username, availableMethods, rememberMe } = state

  const methodInfo = {
    totp: {
      icon: Smartphone,
      title: 'Authenticator App',
      desc: 'Use Google Authenticator, Authy, or similar',
      color: 'blue'
    },
    passkey: {
      icon: Fingerprint,
      title: 'Passkey',
      desc: 'Use Face ID, Touch ID, or security key',
      color: 'green'
    },
    duo: {
      icon: ShieldCheck,
      title: 'Duo Security',
      desc: 'Push notification or phone call',
      color: 'purple'
    }
  }

  const handleMethodSelect = (method: Method) => {
    setSelectedMethod(method)
    setError('')
    setAttemptsRemaining(null)

    // Auto-start Duo or Passkey flows
    if (method === 'duo') {
      handleDuoAuth()
    } else if (method === 'passkey') {
      handlePasskeyAuth()
    }
  }

  const handleTotpSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    setError('')
    setLoading(true)

    try {
      const result: any = await api.verifyTOTPLogin(username, totpCode, useBackupCode, rememberMe)

      if (result.success) {
        // Store token and redirect
        api.setAuthToken(result.token, result.user, result.sessionId)
        navigate('/')
      } else {
        setError(result.message || 'Invalid verification code')
        if (result.attemptsRemaining !== undefined) {
          setAttemptsRemaining(result.attemptsRemaining)
        }
        setTotpCode('')
      }
    } catch (err: unknown) {
      setError(getErrorMessage(err))
      setTotpCode('')
    } finally {
      setLoading(false)
    }
  }

  const handlePasskeyAuth = async () => {
    setError('')
    setLoading(true)

    try {
      // Get authentication options
      const optionsResult: any = await api.getPasskeyAuthenticationOptions(username)

      if (!optionsResult.success) {
        throw new Error(optionsResult.message || 'Failed to start passkey authentication')
      }

      // Helper to convert base64url to Uint8Array
      const base64urlToUint8Array = (base64url: string): Uint8Array => {
        // Convert base64url to base64
        const base64 = base64url.replace(/-/g, '+').replace(/_/g, '/')
        // Decode base64 to binary string
        const binaryString = atob(base64)
        // Convert binary string to Uint8Array
        const bytes = new Uint8Array(binaryString.length)
        for (let i = 0; i < binaryString.length; i++) {
          bytes[i] = binaryString.charCodeAt(i)
        }
        return bytes
      }

      // Convert options to proper format for WebAuthn API
      const options = optionsResult.options
      const publicKeyOptions = {
        ...options,
        challenge: base64urlToUint8Array(options.challenge),
        allowCredentials: options.allowCredentials?.map((cred: any) => ({
          ...cred,
          id: base64urlToUint8Array(cred.id)
        }))
      }

      // Use WebAuthn API to authenticate
      const credential = await navigator.credentials.get({
        publicKey: publicKeyOptions
      }) as any

      if (!credential) {
        throw new Error('Passkey authentication cancelled')
      }

      // Convert credential to base64 for transmission
      const credentialData = {
        id: credential.id,
        rawId: arrayBufferToBase64(credential.rawId),
        response: {
          authenticatorData: arrayBufferToBase64(credential.response.authenticatorData),
          clientDataJSON: arrayBufferToBase64(credential.response.clientDataJSON),
          signature: arrayBufferToBase64(credential.response.signature),
          userHandle: credential.response.userHandle ? arrayBufferToBase64(credential.response.userHandle) : null
        },
        type: credential.type
      }

      // Verify the credential
      const result: any = await api.post('/auth/2fa/passkey/verify-authentication', {
        credential: credentialData,
        username: username,
        rememberMe: rememberMe
      })

      if (result.success) {
        // Store token and redirect
        api.setAuthToken(result.token, result.user, result.sessionId)
        navigate('/')
      } else {
        setError(result.message || 'Passkey authentication failed')
      }
    } catch (err: unknown) {
      console.error('Passkey auth error:', err)
      setError(getErrorMessage(err))
    } finally {
      setLoading(false)
    }
  }

  const handleDuoAuth = async () => {
    setError('')
    setLoading(true)

    try {
      const result: any = await api.createDuoAuth(username, rememberMe)

      if (!result.success) {
        throw new Error(result.message || 'Failed to initiate Duo authentication')
      }

      // Redirect to Duo auth URL
      window.location.href = result.authUrl
    } catch (err: unknown) {
      setError(getErrorMessage(err))
      setLoading(false)
    }
  }

  const handleBackToLogin = () => {
    navigate('/login')
  }

  const handleBackToMethods = () => {
    setSelectedMethod(null)
    setError('')
    setTotpCode('')
    setAttemptsRemaining(null)
  }

  // Helper function to convert ArrayBuffer to base64
  const arrayBufferToBase64 = (buffer: ArrayBuffer): string => {
    const bytes = new Uint8Array(buffer)
    let binary = ''
    for (let i = 0; i < bytes.byteLength; i++) {
      binary += String.fromCharCode(bytes[i])
    }
    return btoa(binary)
  }

  // Show method selector if no method selected or multiple methods available
  if (!selectedMethod && availableMethods.length > 1) {
    return (
      <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 dark:from-gray-900 dark:via-slate-900 dark:to-gray-900 p-4">
        <div className="w-full max-w-md bg-card/80 backdrop-blur-xl border border-white/20 dark:border-white/10 rounded-2xl shadow-2xl p-8">
          <div className="text-center mb-8">
            <Shield className="w-16 h-16 mx-auto mb-4 text-primary" />
            <h2 className="text-2xl font-bold text-foreground mb-2">
              Two-Factor Authentication
            </h2>
            <p className="text-muted-foreground">
              Choose your verification method
            </p>
          </div>

          {error && (
            <div className="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg flex items-start space-x-3">
              <AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5" />
              <p className="text-sm text-red-800 dark:text-red-200">{error}</p>
            </div>
          )}

          <div className="space-y-3">
            {availableMethods.map((method) => {
              const info = methodInfo[method as Method]
              const Icon = info.icon

              return (
                <button
                  key={method}
                  onClick={() => handleMethodSelect(method as Method)}
                  className={`w-full p-4 border-2 rounded-xl transition-all hover:scale-[1.02] hover:shadow-lg flex items-center space-x-4 bg-secondary/30
                    ${info.color === 'blue' ? 'border-primary/50 hover:bg-primary/10' : ''}
                    ${info.color === 'green' ? 'border-green-500/50 hover:bg-green-500/10' : ''}
                    ${info.color === 'purple' ? 'border-purple-500/50 hover:bg-purple-500/10' : ''}
                  `}
                >
                  <Icon className={`w-8 h-8
                    ${info.color === 'blue' ? 'text-primary' : ''}
                    ${info.color === 'green' ? 'text-green-600 dark:text-green-400' : ''}
                    ${info.color === 'purple' ? 'text-purple-600 dark:text-purple-400' : ''}
                  `} />
                  <div className="flex-1 text-left">
                    <div className="font-semibold text-foreground">{info.title}</div>
                    <div className="text-sm text-muted-foreground">{info.desc}</div>
                  </div>
                  <svg className="w-6 h-6 text-muted-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                    <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                  </svg>
                </button>
              )
            })}
          </div>

          <button
            onClick={handleBackToLogin}
            className="mt-6 w-full flex items-center justify-center space-x-2 text-muted-foreground hover:text-foreground transition-colors"
          >
            <ArrowLeft className="w-4 h-4" />
            <span>Back to login</span>
          </button>
        </div>
      </div>
    )
  }

  // Auto-select if only one method
  const currentMethod = selectedMethod || (availableMethods.length === 1 ? availableMethods[0] as Method : null)

  if (!currentMethod) {
    return null
  }

  const info = methodInfo[currentMethod]
  const Icon = info.icon

  // TOTP Verification Form
  if (currentMethod === 'totp') {
    return (
      <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 dark:from-gray-900 dark:via-slate-900 dark:to-gray-900 p-4">
        <div className="w-full max-w-md bg-card/80 backdrop-blur-xl border border-white/20 dark:border-white/10 rounded-2xl shadow-2xl p-8">
          <div className="text-center mb-8">
            <Icon className="w-16 h-16 mx-auto mb-4 text-primary" />
            <h2 className="text-2xl font-bold text-foreground mb-2">
              {info.title}
            </h2>
            <p className="text-muted-foreground">
              {useBackupCode ? 'Enter your backup code' : 'Enter the 6-digit code from your app'}
            </p>
          </div>

          {error && (
            <div className="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-lg flex items-start space-x-3">
              <AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5" />
              <div className="flex-1">
                <p className="text-sm text-red-800 dark:text-red-200">{error}</p>
                {attemptsRemaining !== null && (
                  <p className="text-xs text-red-700 dark:text-red-300 mt-1">
                    {attemptsRemaining} attempts remaining
                  </p>
                )}
              </div>
            </div>
          )}

          <form onSubmit={handleTotpSubmit} className="space-y-6">
            <div>
              <input
                type="text"
                value={totpCode}
                onChange={(e) => setTotpCode(e.target.value.replace(/[^0-9-]/g, ''))}
                placeholder={useBackupCode ? "XXXX-XXXX" : "000000"}
                maxLength={useBackupCode ? 9 : 6}
                className="w-full px-4 py-3 text-center text-2xl tracking-widest border-2 border-border rounded-xl focus:ring-2 focus:ring-primary bg-background text-foreground"
                autoFocus
                required
              />
            </div>

            <button
              type="submit"
              disabled={loading || (!useBackupCode && totpCode.length !== 6) || (useBackupCode && totpCode.length !== 9)}
              className="w-full py-3 bg-primary hover:bg-primary/90 disabled:bg-primary/50 text-primary-foreground font-medium rounded-xl transition-colors"
            >
              {loading ? 'Verifying...' : 'Verify Code'}
            </button>

            <button
              type="button"
              onClick={() => {
                setUseBackupCode(!useBackupCode)
                setTotpCode('')
                setError('')
              }}
              className="w-full text-sm text-primary hover:underline"
            >
              {useBackupCode ? 'Use authenticator code instead' : 'Use backup code instead'}
            </button>
          </form>

          {availableMethods.length > 1 && (
            <button
              onClick={handleBackToMethods}
              className="mt-6 w-full flex items-center justify-center space-x-2 text-muted-foreground hover:text-foreground transition-colors"
            >
              <ArrowLeft className="w-4 h-4" />
              <span>Try another method</span>
            </button>
          )}

          <button
            onClick={handleBackToLogin}
            className="mt-2 w-full flex items-center justify-center space-x-2 text-muted-foreground hover:text-foreground transition-colors text-sm"
          >
            <ArrowLeft className="w-4 h-4" />
            <span>Back to login</span>
          </button>
        </div>
      </div>
    )
  }

  // Passkey or Duo - show loading state
  return (
    <div className="min-h-screen flex items-center justify-center bg-gradient-to-br from-indigo-50 via-purple-50 to-pink-50 dark:from-gray-900 dark:via-slate-900 dark:to-gray-900 p-4">
      <div className="w-full max-w-md bg-card/80 backdrop-blur-xl border border-white/20 dark:border-white/10 rounded-2xl shadow-2xl p-8">
        <div className="text-center mb-8">
          <Icon className={`w-16 h-16 mx-auto mb-4
            ${info.color === 'green' ? 'text-green-600 dark:text-green-400' : ''}
            ${info.color === 'purple' ? 'text-purple-600 dark:text-purple-400' : ''}
          `} />
          <h2 className="text-2xl font-bold text-foreground mb-2">
            {info.title}
          </h2>
          <p className="text-muted-foreground">
            {currentMethod === 'passkey' ? 'Follow the prompts on your device' : 'Redirecting to Duo Security...'}
          </p>
        </div>

        {loading && (
          <div className="flex justify-center">
            <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-primary"></div>
          </div>
        )}

        {error && (
          <div className="mb-6 p-4 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded-xl flex items-start space-x-3">
            <AlertCircle className="w-5 h-5 text-red-600 dark:text-red-400 flex-shrink-0 mt-0.5" />
            <p className="text-sm text-red-800 dark:text-red-200">{error}</p>
          </div>
        )}

        {availableMethods.length > 1 && (
          <button
            onClick={handleBackToMethods}
            className="mt-6 w-full flex items-center justify-center space-x-2 text-muted-foreground hover:text-foreground transition-colors"
          >
            <ArrowLeft className="w-4 h-4" />
            <span>Try another method</span>
          </button>
        )}
      </div>
    </div>
  )
}
