import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'
import type { User } from 'oidc-client-ts'
import { isOidcConfigured, userManager } from './oidcClient'

// Cookie management helper functions
function setCookieFromUser(user: User) {
  if (!user?.access_token) return
  
  const isProduction = window.location.hostname !== 'localhost'
  const domain = isProduction ? '.orfl.xyz' : undefined
  const secure = isProduction
  const sameSite = isProduction ? 'None' : 'Lax'
  
  // Set cookie with JWT token from user
  const cookieValue = `fa_session=${user.access_token}; path=/; ${secure ? 'secure; ' : ''}samesite=${sameSite}${domain ? `; domain=${domain}` : ''}`
  document.cookie = cookieValue
}

function clearFaSessionCookie() {
  const isProduction = window.location.hostname !== 'localhost'
  const domain = isProduction ? '.orfl.xyz' : undefined
  
  // Clear cookie by setting expiration date in the past
  const cookieValue = `fa_session=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT${domain ? `; domain=${domain}` : ''}`
  document.cookie = cookieValue
}

type AuthContextValue = {
  user: User | null
  isLoading: boolean
  isConfigured: boolean
  login: () => Promise<void>
  logout: () => Promise<void>
}

const AuthContext = createContext<AuthContextValue | undefined>(undefined)

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null)
  const [isLoading, setIsLoading] = useState(!!userManager)
  const callbackHandledRef = useRef(false)

  useEffect(() => {
    if (!userManager) {
      return
    }

    let cancelled = false
    userManager
      .getUser()
      .then((loadedUser) => {
        if (!cancelled) {
          setUser(loadedUser ?? null)
          if (loadedUser) {
            setCookieFromUser(loadedUser)
          }
        }
      })
      .finally(() => {
        if (!cancelled) setIsLoading(false)
      })

    return () => {
      cancelled = true
    }
  }, [])

  useEffect(() => {
    const manager = userManager
    if (!manager) return

    const handleLoaded = (nextUser: User) => {
      setUser(nextUser)
      setCookieFromUser(nextUser)
    }
    const handleUnloaded = () => {
      setUser(null)
      clearFaSessionCookie()
    }

    manager.events.addUserLoaded(handleLoaded)
    manager.events.addUserUnloaded(handleUnloaded)
    manager.events.addUserSignedOut(handleUnloaded)

    return () => {
      manager.events.removeUserLoaded(handleLoaded)
      manager.events.removeUserUnloaded(handleUnloaded)
      manager.events.removeUserSignedOut(handleUnloaded)
    }
  }, [])

  useEffect(() => {
    const manager = userManager
    if (!manager || callbackHandledRef.current) return

    const url = new URL(window.location.href)
    const hasAuthParams =
      url.searchParams.has('code') ||
      url.searchParams.has('id_token') ||
      url.searchParams.has('error')

    if (!hasAuthParams) return

    callbackHandledRef.current = true
    manager
      .signinRedirectCallback()
      .then((nextUser) => {
        setUser(nextUser ?? null)
        if (nextUser) {
          setCookieFromUser(nextUser)
        }
      })
      .catch((error) => {
        console.error('Failed to complete sign-in redirect', error)
      })
      .finally(() => {
        const cleanUrl = `${url.origin}${url.pathname}`
        window.history.replaceState({}, document.title, cleanUrl)
      })
  }, [])

  const login = useCallback(async () => {
    const manager = userManager
    if (!manager) {
      console.warn('OIDC is not configured; set VITE_OIDC_* environment variables.')
      return
    }
    await manager.signinRedirect()
  }, [])

  const logout = useCallback(async () => {
    const manager = userManager
    if (!manager) {
      console.warn('OIDC is not configured; set VITE_OIDC_* environment variables.')
      return
    }
    try {
      await manager.signoutRedirect()
    } catch (error) {
      console.error('Failed to sign out via redirect, clearing local session instead.', error)
      await manager.removeUser()
      setUser(null)
      clearFaSessionCookie()
    }
  }, [])

  const value = useMemo<AuthContextValue>(
    () => ({
      user,
      isLoading,
      isConfigured: isOidcConfigured,
      login,
      logout,
    }),
    [isLoading, login, logout, user],
  )

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}

// eslint-disable-next-line react-refresh/only-export-components
export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}
