import { useAuthStore } from "@/lib/api/auth-store"
import { ensureAccessToken } from "@/lib/auth/ensure-access-token"
import { fetchSession, tryRefreshSession } from "@/lib/auth/session-sync"
import {
  isSessionExpired,
  useSessionGuardStore,
} from "@/lib/auth/session-guard-store"
import { isDemoPublicPath } from "@/lib/auth/public-paths"

export type UnauthorizedResolution = "refreshed" | "offline" | "expired"

type HandleUnauthorizedOptions = {
  /** API still returns 401 after a session refresh attempt. */
  forceExpired?: boolean
}

let pending: Promise<UnauthorizedResolution> | null = null

function isBrowserOffline() {
  return typeof navigator !== "undefined" && !navigator.onLine
}

function isDemoRoute() {
  if (typeof window === "undefined") return false
  return isDemoPublicPath(window.location.pathname)
}

function markSessionExpired() {
  if (isDemoRoute()) return
  useAuthStore.getState().logout()
  useSessionGuardStore.getState().setExpired()
}

async function resolveUnauthorized(
  opts?: HandleUnauthorizedOptions
): Promise<UnauthorizedResolution> {
  if (isDemoRoute()) {
    return "refreshed"
  }

  if (isSessionExpired()) {
    return "expired"
  }

  if (opts?.forceExpired) {
    markSessionExpired()
    return "expired"
  }

  if (isBrowserOffline()) {
    useSessionGuardStore.getState().setOffline()
    return "offline"
  }

  if (await tryRefreshSession()) {
    return "refreshed"
  }

  const session = await fetchSession()
  if (session?.authenticated) {
    return "refreshed"
  }

  if (await ensureAccessToken()) {
    return "refreshed"
  }

  markSessionExpired()
  return "expired"
}

/** Verify session after a 401; deduped across concurrent API calls. */
export function handleUnauthorized(
  opts?: HandleUnauthorizedOptions
): Promise<UnauthorizedResolution> {
  if (isDemoRoute()) {
    return Promise.resolve("refreshed")
  }

  if (isSessionExpired()) {
    return Promise.resolve("expired")
  }

  if (opts?.forceExpired) {
    return resolveUnauthorized(opts)
  }

  if (!pending) {
    pending = resolveUnauthorized().finally(() => {
      pending = null
    })
  }
  return pending
}
