"use client"

import { useEffect, useRef, useState, useCallback } from "react"
import { tokenStorage } from "@/src/lib/api/storage"
import { refreshAccessToken } from "@/src/lib/api/auth-refresh"
import { secondsUntilExpiry } from "@/src/lib/auth/token-utils"

const WARN_BEFORE_SECONDS = 3 * 60   // affiche le bandeau à partir de 3 min
const SILENT_REFRESH_SECS = 6 * 60   // refresh silencieux proactif à 6 min
const POLL_INTERVAL_MS    = 5_000

export type SessionState = "active" | "warning" | "expired"

export interface UseSessionMonitorReturn {
  state:       SessionState
  secondsLeft: number
  extend:      () => Promise<void>
  extending:   boolean
}

export function useSessionMonitor(onExpire: () => void): UseSessionMonitorReturn {
  const [state,       setState]       = useState<SessionState>("active")
  const [secondsLeft, setSecondsLeft] = useState<number>(9999)
  const [extending,   setExtending]   = useState(false)

  const intervalRef    = useRef<ReturnType<typeof setInterval> | null>(null)
  const onExpireRef    = useRef(onExpire)
  const extendingRef   = useRef(false)
  const silentTriedRef = useRef(false)
  const mountedRef     = useRef(true)

  onExpireRef.current = onExpire

  // ── Redirige directement vers login, sans passer par le state "expired" ──
  const redirectToLogin = useCallback(() => {
    if (intervalRef.current) clearInterval(intervalRef.current)
    onExpireRef.current()
  }, [])

  const tick = useCallback(() => {
    const access = tokenStorage.getAccess()
    const secs   = secondsUntilExpiry(access)

    if (!mountedRef.current) return
    setSecondsLeft(Math.max(0, secs))

    // ── Token expiré ──────────────────────────────────────────────────────
    if (secs <= 0) {
      if (extendingRef.current) return   // un refresh est déjà en cours

      // Tentative de refresh silencieux (une seule fois par cycle expiré)
      if (!silentTriedRef.current) {
        silentTriedRef.current = true
        extendingRef.current   = true
        refreshAccessToken().then((newAccess) => {
          if (!mountedRef.current) return
          extendingRef.current = false
          if (newAccess) {
            // Refresh réussi → reprend normalement
            const freshSecs = secondsUntilExpiry(newAccess)
            setSecondsLeft(Math.max(0, freshSecs))
            setState("active")
            silentTriedRef.current = false
            if (intervalRef.current) clearInterval(intervalRef.current)
            intervalRef.current = setInterval(tick, POLL_INTERVAL_MS)
          } else {
            // Refresh échoué (refresh token expiré aussi) → login direct
            redirectToLogin()
          }
        })
        return  // attend le résultat du refresh
      }

      // Déjà tenté, toujours expiré → login direct
      redirectToLogin()
      return
    }

    // ── Zone d'avertissement (<3 min) ─────────────────────────────────────
    if (secs <= WARN_BEFORE_SECONDS) {
      setState("warning")
      silentTriedRef.current = false
      return
    }

    // ── Zone de refresh silencieux proactif (3–6 min) ─────────────────────
    if (secs <= SILENT_REFRESH_SECS && !silentTriedRef.current && !extendingRef.current) {
      silentTriedRef.current = true
      refreshAccessToken().then((newAccess) => {
        if (newAccess && mountedRef.current) {
          const freshSecs = secondsUntilExpiry(newAccess)
          setSecondsLeft(Math.max(0, freshSecs))
          setState("active")
          silentTriedRef.current = false
        }
        // Échec silencieux : le polling continuera et affichera le bandeau
      })
    }

    setState("active")
  }, [redirectToLogin])

  useEffect(() => {
    mountedRef.current = true
    tick()
    intervalRef.current = setInterval(tick, POLL_INTERVAL_MS)
    return () => {
      mountedRef.current = false
      if (intervalRef.current) clearInterval(intervalRef.current)
    }
  }, [tick])

  // ── Bouton "Rester connecté" ──────────────────────────────────────────────
  const extend = useCallback(async () => {
    if (extendingRef.current) return
    extendingRef.current = true
    setExtending(true)
    try {
      const newAccess = await refreshAccessToken()
      if (!mountedRef.current) return
      if (newAccess) {
        // Succès → reprend la session normalement
        const freshSecs = secondsUntilExpiry(newAccess)
        setSecondsLeft(Math.max(0, freshSecs))
        setState("active")
        silentTriedRef.current = false
        if (intervalRef.current) clearInterval(intervalRef.current)
        intervalRef.current = setInterval(tick, POLL_INTERVAL_MS)
      } else {
        // Refresh échoué → impossible de prolonger → login direct
        // Note: reset extendingRef AVANT redirectToLogin pour que tick()
        // n'entre pas en conflit si jamais il se déclenchait en parallèle
        extendingRef.current = false
        redirectToLogin()
      }
    } finally {
      if (mountedRef.current) {
        extendingRef.current = false
        setExtending(false)
      }
    }
  }, [tick, redirectToLogin])

  return { state, secondsLeft, extend, extending }
}
