'use client'

import { useState, useEffect, useRef } from 'react'
import { useAuth, useAuthContext, useFeatures } from '../contexts/AuthContext'
import { useAllauthAPI } from '../contexts/APIContext'
import { useStyles } from '../contexts/StylesContext'
import { getAuthDetails } from '../api'
import { AuthenticatorType } from '../defines'
import { AuthSettings } from './settings/AuthSettings'
import { AuthCard } from './AuthCard'
import { AuthDjangoForm } from './AuthDjangoForm'
import { Button } from './settings/SettingsComponents'
import { LoginView } from './views/LoginView'
import { SignupView } from './views/SignupView'
import { MFAChooserView } from './views/MFAChooserView'
import { MFAWebAuthnView } from './views/MFAWebAuthnView'
import { MFATOTPView } from './views/MFATOTPView'
import { MFARecoveryCodesView } from './views/MFARecoveryCodesView'

/**
 * All possible views in the AllauthUI component.
 * Views are rendered based on state, not URLs.
 */
export type AllauthUIView =
    // Auth views (for unauthenticated users)
    | 'login'
    | 'signup'
    | 'resetPassword'
    | 'resetPasswordSent'
    | 'requestCode'
    | 'confirmCode'
    // MFA views (during auth flow)
    | 'mfaChooser'
    | 'mfaTotp'
    | 'mfaWebauthn'
    | 'mfaRecoveryCodes'
    // Authenticated views
    | 'settings'
    | 'logout'

/**
 * Controls how AllauthUI behaves regarding auth/settings transitions.
 *
 * - `'auto'` (default): Full SPA - shows auth views when not authenticated,
 *   automatically transitions to settings after login, and back to login after logout.
 *
 * - `'auth'`: Auth-only mode - only shows auth views (login, signup, MFA, etc.).
 *   Never shows settings. Use `onAuthenticated` to handle post-login navigation.
 *   Ideal for a dedicated login page.
 *
 * - `'settings'`: Settings-only mode - only shows settings views.
 *   If not authenticated, calls `onUnauthenticated` or shows nothing.
 *   Ideal for a dedicated settings page.
 */
export type AllauthUIMode = 'auto' | 'auth' | 'settings'

interface AllauthUIProps {
    /**
     * Controls auth/settings transition behavior.
     * @default 'auto'
     */
    mode?: AllauthUIMode

    /**
     * Initial view when component mounts (for 'auto' and 'auth' modes).
     * Defaults to 'login' for unauthenticated, 'settings' for authenticated (in auto mode).
     */
    initialView?: AllauthUIView

    /**
     * Called when authentication completes successfully.
     * Required for 'auth' mode to handle post-login navigation.
     */
    onAuthenticated?: () => void

    /**
     * Called when user is not authenticated (for 'settings' mode).
     * Use this to redirect to login page.
     */
    onUnauthenticated?: () => void

    /**
     * Called when user logs out.
     * In 'auto' mode, defaults to showing login view.
     */
    onLogout?: () => void

    /**
     * Which settings sections to show.
     * Defaults to all sections.
     */
    settingsSections?: Array<'profile' | 'emails' | 'password' | 'passkeys' | 'connections' | 'mfa' | 'sessions'>

    /**
     * OAuth callback URL for social login providers.
     */
    oauthCallbackUrl?: string
}

/**
 * AllauthUI is the main component for rendering auth UI.
 *
 * It can operate in three modes:
 * - `'auto'` (default): Full SPA handling login, MFA, settings, and logout
 * - `'auth'`: Auth-only for dedicated login pages
 * - `'settings'`: Settings-only for dedicated settings pages
 *
 * @example
 * ```tsx
 * // Full SPA mode (default) - handles everything
 * <AllauthUI />
 *
 * // Auth-only mode - for a dedicated login page
 * <AllauthUI mode="auth" onAuthenticated={() => router.push('/dashboard')} />
 *
 * // Settings-only mode - for a dedicated settings page
 * <AllauthUI mode="settings" onUnauthenticated={() => router.push('/login')} />
 * ```
 */
export function AllauthUI({
    mode = 'auto',
    initialView,
    onAuthenticated,
    onUnauthenticated,
    onLogout,
    settingsSections,
    oauthCallbackUrl,
}: AllauthUIProps) {
    const { isAuthenticated, pendingFlow } = useAuth()
    const { refresh } = useAuthContext()
    const api = useAllauthAPI()
    const styles = useStyles()
    const features = useFeatures()

    // Get available MFA types from pending flow
    const mfaTypes = pendingFlow?.types || []

    // Internal view state
    const [view, setView] = useState<AllauthUIView>(() => {
        if (initialView) return initialView

        // Settings mode always starts at settings
        if (mode === 'settings') return 'settings'

        // Auth mode always starts at login (or MFA if pending)
        if (mode === 'auth') {
            if (pendingFlow) {
                return mfaTypes.length === 1 ? getMFAView(mfaTypes[0]) : 'mfaChooser'
            }
            return 'login'
        }

        // Auto mode: settings if authenticated, login otherwise
        if (isAuthenticated) return 'settings'
        if (pendingFlow) {
            return mfaTypes.length === 1 ? getMFAView(mfaTypes[0]) : 'mfaChooser'
        }
        return 'login'
    })

    // Track auth state changes
    const wasAuthenticated = useRef(isAuthenticated)
    const hadPendingFlow = useRef(!!pendingFlow)

    // Handle auth state transitions
    useEffect(() => {
        // User just became authenticated
        if (!wasAuthenticated.current && isAuthenticated) {
            if (onAuthenticated) {
                onAuthenticated()
            } else if (mode === 'auto') {
                setView('settings')
            }
            // In 'auth' mode without onAuthenticated, do nothing (stay on current view)
        }

        // User just logged out
        if (wasAuthenticated.current && !isAuthenticated) {
            if (onLogout) {
                onLogout()
            } else if (mode === 'auto') {
                setView('login')
            } else if (mode === 'settings' && onUnauthenticated) {
                onUnauthenticated()
            }
        }

        wasAuthenticated.current = isAuthenticated
    }, [isAuthenticated, onAuthenticated, onUnauthenticated, onLogout, mode])

    // Handle MFA flow transitions
    useEffect(() => {
        if (pendingFlow && !hadPendingFlow.current) {
            // New MFA flow started
            if (mfaTypes.length === 1) {
                setView(getMFAView(mfaTypes[0]))
            } else if (mfaTypes.length > 1) {
                setView('mfaChooser')
            }
        }
        if (!pendingFlow && hadPendingFlow.current && isAuthenticated) {
            // MFA completed successfully
            if (onAuthenticated) {
                onAuthenticated()
            } else if (mode === 'auto') {
                setView('settings')
            }
        }
        hadPendingFlow.current = !!pendingFlow
    }, [pendingFlow, mfaTypes, isAuthenticated, onAuthenticated, mode])

    // Settings mode: handle unauthenticated state
    useEffect(() => {
        if (mode === 'settings' && !isAuthenticated && onUnauthenticated) {
            onUnauthenticated()
        }
    }, [mode, isAuthenticated, onUnauthenticated])

    // Handle logout
    const handleLogout = async () => {
        await api.session.logout()
        await refresh()
        if (onLogout) {
            onLogout()
        } else if (mode === 'auto') {
            setView('login')
        }
        // In settings mode, the useEffect will call onUnauthenticated
    }

    // Called after successful login/signup - check for MFA or complete auth
    const handleAuthSuccess = async () => {
        const newAuth = await refresh()
        const details = getAuthDetails(newAuth)

        // If fully authenticated, handle completion
        if (details.isAuthenticated) {
            if (onAuthenticated) {
                onAuthenticated()
            } else if (mode === 'auto') {
                setView('settings')
            }
            // In 'auth' mode without onAuthenticated, stay on current view
        }
        // If MFA pending, the useEffect will handle the view transition
    }

    // Render based on current view
    switch (view) {
        // ============================================
        // Authenticated views
        // ============================================
        case 'settings':
            // In auth mode, never show settings
            if (mode === 'auth') {
                return null
            }
            // Not authenticated - handle based on mode
            if (!isAuthenticated) {
                if (mode === 'settings' && onUnauthenticated) {
                    // Will be handled by useEffect
                    return null
                }
                // Auto mode: switch to login
                setView('login')
                return null
            }
            return (
                <AuthSettings
                    sections={settingsSections}
                    onSignOut={() => setView('logout')}
                />
            )

        case 'logout':
            if (!isAuthenticated) {
                if (mode === 'auto') {
                    setView('login')
                }
                return null
            }
            return (
                <AuthCard
                    title="Sign Out"
                    subtitle="Are you sure you want to sign out?"
                    footerLinks={[
                        { label: 'Cancel', onClick: () => setView('settings') },
                    ]}
                >
                    <div className={styles.form}>
                        <Button onClick={handleLogout}>
                            Sign Out
                        </Button>
                    </div>
                </AuthCard>
            )

        // ============================================
        // MFA views
        // ============================================
        case 'mfaChooser':
            return (
                <MFAChooserView
                    types={mfaTypes}
                    onSuccess={handleAuthSuccess}
                    onCancel={() => setView('login')}
                />
            )

        case 'mfaTotp':
            return (
                <MFATOTPView
                    onSuccess={handleAuthSuccess}
                    onCancel={() => setView('login')}
                    onBack={mfaTypes.length > 1 ? () => setView('mfaChooser') : undefined}
                />
            )

        case 'mfaWebauthn':
            return (
                <MFAWebAuthnView
                    onSuccess={handleAuthSuccess}
                    onCancel={() => setView('login')}
                    onBack={mfaTypes.length > 1 ? () => setView('mfaChooser') : undefined}
                />
            )

        case 'mfaRecoveryCodes':
            return (
                <MFARecoveryCodesView
                    onSuccess={handleAuthSuccess}
                    onCancel={() => setView('login')}
                    onBack={mfaTypes.length > 1 ? () => setView('mfaChooser') : undefined}
                />
            )

        // ============================================
        // Password reset views
        // ============================================
        case 'resetPassword':
            return (
                <AuthDjangoForm
                    formName="reset_password"
                    onSuccess={() => setView('resetPasswordSent')}
                    footerLinks={[
                        { label: 'Back to Sign In', onClick: () => setView('login') },
                    ]}
                />
            )

        case 'resetPasswordSent':
            return (
                <AuthCard
                    title="Check Your Email"
                    subtitle="If an account exists with that email, we've sent password reset instructions."
                    footerLinks={[
                        { label: 'Back to Sign In', onClick: () => setView('login') },
                    ]}
                />
            )

        // ============================================
        // Login by code views
        // ============================================
        case 'requestCode':
            // If login by code is disabled, redirect to login
            if (!features.loginByCodeEnabled) {
                setView('login')
                return null
            }
            return (
                <AuthDjangoForm
                    formName="request_login_code"
                    onSuccess={() => setView('confirmCode')}
                    footerLinks={[
                        { label: 'Sign in with password instead', onClick: () => setView('login') },
                    ]}
                />
            )

        case 'confirmCode':
            // If login by code is disabled, redirect to login
            if (!features.loginByCodeEnabled) {
                setView('login')
                return null
            }
            return (
                <AuthDjangoForm
                    formName="confirm_login_code"
                    onSuccess={handleAuthSuccess}
                    footerLinks={[
                        { label: 'Request a new code', onClick: () => setView('requestCode') },
                        { label: 'Sign in with password instead', onClick: () => setView('login') },
                    ]}
                />
            )

        // ============================================
        // Signup view
        // ============================================
        case 'signup':
            // If signup is disabled, redirect to login
            if (!features.signupEnabled) {
                setView('login')
                return null
            }
            return (
                <SignupView
                    onSuccess={handleAuthSuccess}
                    onLoginClick={() => setView('login')}
                />
            )

        // ============================================
        // Login view (default)
        // ============================================
        case 'login':
        default:
            return (
                <LoginView
                    onSuccess={handleAuthSuccess}
                    // Only provide signup callback if signups are enabled
                    onSignupClick={features.signupEnabled ? () => setView('signup') : undefined}
                    onForgotPasswordClick={() => setView('resetPassword')}
                    // Only provide login-by-code callback if feature is enabled
                    onLoginByCodeClick={features.loginByCodeEnabled ? () => setView('requestCode') : undefined}
                    oauthCallbackUrl={oauthCallbackUrl}
                />
            )
    }
}

/**
 * Get the view name for a given MFA authenticator type.
 */
function getMFAView(type: string): AllauthUIView {
    switch (type) {
        case AuthenticatorType.TOTP:
            return 'mfaTotp'
        case AuthenticatorType.WEBAUTHN:
            return 'mfaWebauthn'
        case AuthenticatorType.RECOVERY_CODES:
            return 'mfaRecoveryCodes'
        default:
            return 'mfaChooser'
    }
}
