"use client"

import { useCallback, useEffect, useState, type ReactNode } from "react"
import { usePathname, useRouter } from "next/navigation"
import { useAuthStore, AUTH_STORAGE_KEY, LEGACY_AUTH_KEYS } from "@/lib/api/auth-store"
import { isOidcConfigured } from "@/lib/auth/oidc-config"
import {
  fetchSession,
  applySessionToStore,
  type SessionPayload,
} from "@/lib/auth/session-sync"
import {
  isSessionExpired,
  useSessionGuardStore,
} from "@/lib/auth/session-guard-store"
import { isAuthPublicPath } from "@/lib/auth/public-paths"

const REFRESH_LEAD_MS = 5 * 60 * 1000
const REFRESH_CHECK_MS = 60 * 1000

function isPublicPath(pathname: string) {
  return isAuthPublicPath(pathname)
}

export function AuthProvider({ children }: { children: ReactNode }) {
  const pathname = usePathname()
  const router = useRouter()
  const logout = useAuthStore((s) => s.logout)
  const isAuthenticated = useAuthStore((s) => s.isAuthenticated)
  const [ready, setReady] = useState(() => !isOidcConfigured())

  const applySession = useCallback(
    (data: SessionPayload) => applySessionToStore(data),
    []
  )

  const syncSession = useCallback(async () => {
    const data = await fetchSession()
    if (data && applySession(data)) return true
    logout()
    return false
  }, [applySession, logout])

  useEffect(() => {
    let cancelled = false

    async function bootstrap() {
      if (!isOidcConfigured()) {
        setReady(true)
        return
      }

      const data = await fetchSession()
      if (cancelled) return

      if (data && applySession(data)) {
        setReady(true)
        return
      }

      const hadMemoryAuth = useAuthStore.getState().isAuthenticated()
      logout()
      if (hadMemoryAuth && !isPublicPath(pathname) && !isSessionExpired()) {
        useSessionGuardStore.getState().setExpired()
      }
      setReady(true)
    }

    if (!useAuthStore.persist.hasHydrated()) {
      const unsubHydrate = useAuthStore.persist.onFinishHydration(() => {
        void bootstrap()
      })
      return () => {
        cancelled = true
        unsubHydrate()
      }
    }

    void bootstrap()
    return () => {
      cancelled = true
    }
  }, [applySession, logout, pathname])

  useEffect(() => {
    if (!ready || !isOidcConfigured()) return

    const interval = setInterval(() => {
      const { accessToken, expiresAt } = useAuthStore.getState()
      if (!accessToken || !expiresAt) return
      if (Date.now() >= expiresAt - REFRESH_LEAD_MS) {
        void syncSession()
      }
    }, REFRESH_CHECK_MS)

    return () => clearInterval(interval)
  }, [ready, syncSession])

  useEffect(() => {
    if (!ready || !isOidcConfigured()) return
    if (isPublicPath(pathname)) return
    if (isAuthenticated()) return

    let cancelled = false
    void syncSession().then((ok) => {
      if (cancelled || ok) return
      if (useSessionGuardStore.getState().status === "expired") return
      const returnTo = encodeURIComponent(pathname)
      router.replace(`/login?returnTo=${returnTo}`)
    })

    return () => {
      cancelled = true
    }
  }, [ready, pathname, isAuthenticated, router, syncSession])

  return <>{children}</>
}

export function useAuthLogout() {
  const logout = useAuthStore((s) => s.logout)
  const router = useRouter()

  return async () => {
    await fetch("/api/auth/logout", { method: "POST", credentials: "include" })
    logout()
    if (typeof window !== "undefined") {
      localStorage.removeItem(AUTH_STORAGE_KEY)
      for (const legacy of LEGACY_AUTH_KEYS) {
        localStorage.removeItem(legacy)
      }
    }
    router.replace("/login")
  }
}
