"use client"; import { createContext, useContext, useState, useEffect, type ReactNode, } from "react"; import { useRouter } from "next/navigation"; import { api, setRefreshCallback } from "@/lib/api"; const ACCESS_KEY_LOCAL = "k-tv-token"; const ACCESS_KEY_SESSION = "k-tv-token-session"; const REFRESH_KEY = "k-tv-refresh-token"; interface AuthContextValue { token: string | null; refreshToken: string | null; /** Always true (lazy init reads storage synchronously) */ isLoaded: boolean; setTokens: (access: string | null, refresh: string | null, remember: boolean) => void; } const AuthContext = createContext(null); export function AuthProvider({ children }: { children: ReactNode }) { const router = useRouter(); const [token, setTokenState] = useState(() => { try { return sessionStorage.getItem(ACCESS_KEY_SESSION) ?? localStorage.getItem(ACCESS_KEY_LOCAL); } catch { return null; } }); const [refreshToken, setRefreshTokenState] = useState(() => { try { return localStorage.getItem(REFRESH_KEY); } catch { return null; } }); const setTokens = (access: string | null, refresh: string | null, remember: boolean) => { try { if (access === null) { sessionStorage.removeItem(ACCESS_KEY_SESSION); localStorage.removeItem(ACCESS_KEY_LOCAL); localStorage.removeItem(REFRESH_KEY); } else if (remember) { localStorage.setItem(ACCESS_KEY_LOCAL, access); sessionStorage.removeItem(ACCESS_KEY_SESSION); if (refresh) { localStorage.setItem(REFRESH_KEY, refresh); } else { localStorage.removeItem(REFRESH_KEY); } } else { sessionStorage.setItem(ACCESS_KEY_SESSION, access); localStorage.removeItem(ACCESS_KEY_LOCAL); localStorage.removeItem(REFRESH_KEY); } } catch { // storage unavailable — state-only fallback } setTokenState(access); setRefreshTokenState(refresh); }; // Wire up the transparent refresh callback in api.ts useEffect(() => { if (refreshToken) { setRefreshCallback(async () => { try { const data = await api.auth.refresh(refreshToken); const newRefresh = data.refresh_token ?? null; setTokens(data.access_token, newRefresh, true); return data.access_token; } catch { setTokens(null, null, false); router.push("/login"); return null; } }); } else { setRefreshCallback(null); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [refreshToken]); return ( {children} ); } export function useAuthContext() { const ctx = useContext(AuthContext); if (!ctx) throw new Error("useAuthContext must be used within AuthProvider"); return ctx; }