// useAuth.tsx
import { AuthContext } from '@/contexts/AuthContext';
import type { GenerateTokenResponse } from '@/features/authorization/api/identityAPI';
import axios from 'axios';
import { useEffect, useState, type ReactNode } from 'react';

export const ACCESS_TOKEN_KEY: 'access_token' = 'access_token' as const;
export const REFRESH_TOKEN_KEY: 'refresh_token' = 'refresh_token' as const;
export const EXPIRES_IN_KEY: 'expires_in' = 'expires_in' as const;

let inMemoryToken: string | null = null;
let expiresAt = 0;

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [accessToken, setAccessToken] = useState<string | null>(
    sessionStorage.getItem(ACCESS_TOKEN_KEY),
  );

  // Initialize from sessionStorage (page reload)
  useEffect(() => {
    const token = sessionStorage.getItem(ACCESS_TOKEN_KEY);
    const exp = Number(sessionStorage.getItem(EXPIRES_IN_KEY) || 0);

    if (token && Date.now() < exp) {
      inMemoryToken = token;
      expiresAt = exp;
      setAccessToken(token);
    }
  }, []);

  // Background refresh
  useEffect(() => {
    const handleRefreshTokenIfNeeded = async () => {
      if (!inMemoryToken) return;
      if (Date.now() < expiresAt - 60_000) return; // still valid (buffer)

      await refreshAccessToken();
      setAccessToken(inMemoryToken);
    };

    handleRefreshTokenIfNeeded();

    const interval = setInterval(async () => {
      await handleRefreshTokenIfNeeded();
    }, 30_000);

    return () => clearInterval(interval);
  }, []);

  function login(tokens: {
    access_token: string;
    refresh_token: string;
    expires_in: number;
  }) {
    inMemoryToken = tokens.access_token;
    expiresAt = Date.now() + tokens.expires_in * 1000;

    sessionStorage.setItem(ACCESS_TOKEN_KEY, tokens.access_token);
    sessionStorage.setItem(REFRESH_TOKEN_KEY, tokens.refresh_token);
    sessionStorage.setItem(EXPIRES_IN_KEY, String(expiresAt));

    setAccessToken(tokens.access_token);
  }

  function logout() {
    inMemoryToken = null;
    expiresAt = 0;
    sessionStorage.clear();
    setAccessToken(null);
  }

  function getToken() {
    return inMemoryToken;
  }

  async function refreshAccessToken() {
    const refreshToken = sessionStorage.getItem(REFRESH_TOKEN_KEY);
    if (!refreshToken) {
      logout();
      return;
    }

    try {
      const result = await axios.post<GenerateTokenResponse>(
        import.meta.env.VITE_IDENTITY_URL,
        new URLSearchParams({
          grant_type: 'refresh_token',
          refresh_token: refreshToken,
          client_id: import.meta.env.VITE_IDENTITY_CLIENT_ID, // from your token payload
        }),
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded',
          },
        },
      );

      if (result.data.access_token) {
        inMemoryToken = result.data.access_token;
        expiresAt = Date.now() + result.data.expires_in * 1000;

        sessionStorage.setItem(ACCESS_TOKEN_KEY, inMemoryToken as string);
        sessionStorage.setItem(EXPIRES_IN_KEY, String(expiresAt));

        setAccessToken(inMemoryToken);
      } else {
        logout();
      }
    } catch {
      logout();
    }
  }

  return (
    <AuthContext.Provider value={{ accessToken, getToken, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};
