'use client'

import { ReactNode, useEffect, useState } from 'react'
import { useDjangoCSRClient, Auth } from 'mizan/client/react'
import type { RouterAdapter } from '../adapters/router'
import type { InitialAuth } from '../hydration'
import { AuthContext } from './AuthContext'
import { ConfigContext } from './ConfigContext'
import { StylesContext } from './StylesContext'
import { RouterContext } from './RouterContext'
import { AllauthConfig } from '../config'
import { AuthClassNames } from '../styles/types'
import { createAPI } from '../api'

export interface AllauthContextProps {
    children: ReactNode

    /** Router adapter for navigation */
    router: RouterAdapter

    /** Optional initial auth state from getInitialAuth() - if not provided, fetches client-side */
    hydration?: InitialAuth

    /** Library configuration (basePath, routes) */
    allauthConfig?: Partial<AllauthConfig>

    /** CSS class names for styling components */
    classNames?: AuthClassNames
}

/**
 * Core AllauthContext - sets up all contexts for the allauth library.
 *
 * IMPORTANT: AllauthContext must be wrapped by DjangoContext, which provides
 * user data via useUser(). The typical setup is:
 *
 * ```tsx
 * <DjangoContext client={client} hydration={djangoHydration}>
 *   <AllauthContext hydration={allauthHydration}>
 *     {children}
 *   </AllauthContext>
 * </DjangoContext>
 * ```
 *
 * If hydration is provided (from SSR), uses it immediately.
 * If not provided, fetches initial auth state client-side using the CSR client.
 *
 * For Next.js apps, use NextAllauthContext instead which handles the router automatically.
 */
export function AllauthContext({
    children,
    router,
    hydration,
    allauthConfig,
    classNames,
}: AllauthContextProps) {
    const client = useDjangoCSRClient(Auth.SESSION)
    const [initialAuth, setInitialAuth] = useState<InitialAuth | null>(hydration ?? null)
    const [loading, setLoading] = useState(!hydration)

    useEffect(() => {
        if (hydration) return // Already have SSR hydration

        const fetchInitialAuth = async () => {
            try {
                const authRequest = async (method: string, path: string, data?: any, headers?: Record<string, string>) => {
                    const resp = await client.request(method, `/_allauth/browser/v1${path}`, data, headers)
                    if (resp.status >= 500) {
                        throw new Error(`Allauth request failed: ${resp.status} ${resp.statusText}`)
                    }
                    return resp.json()
                }

                const api = createAPI((method, path, data?, headers?) =>
                    authRequest(method, path, { ...(data as object), client: 'browser' }, headers)
                )

                const [config, auth] = await Promise.all([
                    api.getConfig(),
                    api.session.getStatus(),
                ])

                setInitialAuth({ config, auth })
            } catch (e) {
                console.error('[AllauthContext] Failed to fetch initial auth:', e)
                setInitialAuth({
                    config: { status: 200, data: {} },
                    auth: { status: 401, data: {} },
                })
            } finally {
                setLoading(false)
            }
        }

        fetchInitialAuth()
    }, [client, hydration])

    if (loading || !initialAuth) {
        return null
    }

    return (
        <RouterContext router={router}>
            <ConfigContext config={allauthConfig}>
                <StylesContext classNames={classNames}>
                    <AuthContext
                        config={initialAuth.config}
                        auth={initialAuth.auth}
                    >
                        {children}
                    </AuthContext>
                </StylesContext>
            </ConfigContext>
        </RouterContext>
    )
}
