'use client'

import {
    createContext,
    useContext,
    useState,
    useCallback,
    useMemo,
    type ReactNode,
} from 'react'
import { createDjangoCSRClient, Auth } from './index'
import type { BaseUser, AuthDetails, AuthRoutes } from './types'

/**
 * Auth state provided by AuthContext.
 */
export interface AuthState<TUser extends BaseUser = BaseUser> {
    /** Current user (null if not authenticated) */
    user: TUser | null
    /** Whether auth state is loading */
    isLoading: boolean
    /** Refresh user from server */
    refresh: () => Promise<TUser | null>
}

const Context = createContext<AuthState | null>(null)

/**
 * Default routes configuration.
 */
export const defaultRoutes: AuthRoutes = {
    login: '/auth/login',
    authenticated: '/dashboard',
}

const RoutesContext = createContext<AuthRoutes>(defaultRoutes)

export interface AuthContextProps<TUser extends BaseUser = BaseUser> {
    children: ReactNode
    /** Initial user from SSR hydration (null if not authenticated) */
    user?: TUser | null
    /** API endpoint to fetch user data (default: '/api/auth/me/') */
    userEndpoint?: string
    /** Route configuration for guards */
    routes?: Partial<AuthRoutes>
}

/**
 * Base auth context for Django-React apps.
 *
 * Provides user state from a simple /me endpoint.
 * For allauth integration, use AllauthContext instead.
 */
// Create client once at module level (session auth, no dynamic config needed)
const client = createDjangoCSRClient(Auth.SESSION)

export function AuthContext<TUser extends BaseUser = BaseUser>({
    children,
    user: initialUser = null,
    userEndpoint = '/api/auth/me/',
    routes,
}: AuthContextProps<TUser>) {
    const [user, setUser] = useState<TUser | null>(initialUser)
    const [isLoading, setIsLoading] = useState(false)

    const refresh = useCallback(async (): Promise<TUser | null> => {
        setIsLoading(true)
        try {
            const resp = await client.request('GET', userEndpoint)
            if (resp.ok) {
                const userData = await resp.json()
                setUser(userData)
                return userData
            } else if (resp.status === 401 || resp.status === 403) {
                setUser(null)
                return null
            }
            throw new Error(`Failed to fetch user: ${resp.status}`)
        } catch (e) {
            console.error('[AuthContext] Failed to fetch user:', e)
            return null
        } finally {
            setIsLoading(false)
        }
    }, [userEndpoint])

    const authState = useMemo<AuthState<TUser>>(() => ({
        user,
        isLoading,
        refresh,
    }), [user, isLoading, refresh])

    const routesValue = useMemo(() => ({
        ...defaultRoutes,
        ...routes,
    }), [routes])

    return (
        <RoutesContext value={routesValue}>
            <Context value={authState}>
                {children}
            </Context>
        </RoutesContext>
    )
}

/**
 * Hook to access auth state.
 * Throws if used outside AuthContext.
 */
export function useAuthState<TUser extends BaseUser = BaseUser>(): AuthState<TUser> {
    const ctx = useContext(Context)
    if (!ctx) throw new Error('useAuthState must be used within AuthContext')
    return ctx as AuthState<TUser>
}

/**
 * Hook to access current user.
 * Returns null if not authenticated.
 */
export function useUser<TUser extends BaseUser = BaseUser>(): TUser | null {
    return useAuthState<TUser>().user
}

/**
 * Hook to access auth details (isAuthenticated, isStaff, etc.)
 */
export function useAuth(): AuthDetails {
    const user = useUser()
    return {
        isAuthenticated: user !== null,
        isStaff: user?.is_staff ?? false,
        isSuperuser: user?.is_superuser ?? false,
    }
}

/**
 * Hook to access route configuration.
 */
export function useAuthRoutes(): AuthRoutes {
    return useContext(RoutesContext)
}
