import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'
import type { AuthProvider, UserIdentity, LoginParams } from '../types'

export interface AuthContextValue {
  /** Whether the user is authenticated */
  isAuthenticated: boolean
  /** Current user identity */
  identity?: UserIdentity
  /** User permissions */
  permissions?: string[]
  /** Whether auth is being checked */
  isLoading: boolean
  /** Login function */
  login: (params: LoginParams) => Promise<void>
  /** Logout function */
  logout: () => Promise<void>
  /** Refresh auth state */
  refreshAuth: () => Promise<void>
}

export const AuthContext = createContext<AuthContextValue | null>(null)

export interface AuthProviderProps {
  children: ReactNode
  authProvider: AuthProvider
}

/**
 * Provides authentication state and methods to child components.
 *
 * @example
 * ```tsx
 * const myAuthProvider: AuthProvider = {
 *   login: async ({ username, password }) => { ... },
 *   logout: async () => { ... },
 *   checkAuth: async () => { ... },
 *   checkError: async (error) => { ... },
 *   getIdentity: async () => ({ id: '1', fullName: 'John' }),
 *   getPermissions: async () => ['admin'],
 * }
 *
 * <AuthProvider authProvider={myAuthProvider}>
 *   <App />
 * </AuthProvider>
 * ```
 */
export function AuthProvider({ children, authProvider }: AuthProviderProps) {
  const [isAuthenticated, setIsAuthenticated] = useState(false)
  const [identity, setIdentity] = useState<UserIdentity>()
  const [permissions, setPermissions] = useState<string[]>()
  const [isLoading, setIsLoading] = useState(true)

  const refreshAuth = useCallback(async () => {
    setIsLoading(true)
    try {
      await authProvider.checkAuth()
      const [newIdentity, newPermissions] = await Promise.all([
        authProvider.getIdentity(),
        authProvider.getPermissions(),
      ])
      setIdentity(newIdentity)
      setPermissions(newPermissions)
      setIsAuthenticated(true)
    } catch {
      setIsAuthenticated(false)
      setIdentity(undefined)
      setPermissions(undefined)
    } finally {
      setIsLoading(false)
    }
  }, [authProvider])

  useEffect(() => {
    refreshAuth()
  }, [refreshAuth])

  const login = useCallback(async (params: LoginParams) => {
    await authProvider.login(params)
    await refreshAuth()
  }, [authProvider, refreshAuth])

  const logout = useCallback(async () => {
    await authProvider.logout()
    setIsAuthenticated(false)
    setIdentity(undefined)
    setPermissions(undefined)
  }, [authProvider])

  return (
    <AuthContext.Provider
      value={{
        isAuthenticated,
        identity,
        permissions,
        isLoading,
        login,
        logout,
        refreshAuth,
      }}
    >
      {children}
    </AuthContext.Provider>
  )
}

/**
 * Hook to access authentication state and methods.
 * Must be used within an AuthProvider.
 *
 * @example
 * ```tsx
 * const { isAuthenticated, identity, login, logout } = useAuth()
 *
 * if (!isAuthenticated) {
 *   return <LoginPage onSubmit={login} />
 * }
 * ```
 */
export function useAuth(): AuthContextValue {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}
