import React, { createContext, useCallback, useContext, useEffect, useState } from "react";
import axios from "axios";
import { adminEndpoints } from "./api";
import { parseAdminLoginError } from "./lib/loginErrors";

const TOKEN_KEY = "admin_access_token";

function getToken(): string | null {
  return sessionStorage.getItem(TOKEN_KEY);
}

function setToken(token: string | null) {
  if (token) sessionStorage.setItem(TOKEN_KEY, token);
  else sessionStorage.removeItem(TOKEN_KEY);
}

const axiosInstance = axios.create({
  headers: { "Content-Type": "application/json" },
});

axiosInstance.interceptors.request.use((config) => {
  const token = getToken();
  if (token) config.headers.Authorization = `Bearer ${token}`;
  return config;
});

type User = { id: number; name: string; email: string; role: string };

type AdminAuthContextValue = {
  user: User | null;
  loading: boolean;
  authenticated: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  checkSession: () => Promise<void>;
};

const AdminAuthContext = createContext<AdminAuthContextValue | null>(null);

export function AdminAuthProvider({ children }: { children: React.ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [loading, setLoading] = useState(true);

  const checkSession = useCallback(async () => {
    const token = getToken();
    if (!token) {
      setUser(null);
      setLoading(false);
      return;
    }
    try {
      const res = await axiosInstance.get(adminEndpoints.user);
      const u = res.data?.user;
      if (u) setUser({ ...u, accessToken: token });
      else setUser(null);
    } catch {
      setToken(null);
      setUser(null);
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    checkSession();
  }, [checkSession]);

  const login = useCallback(async (email: string, password: string) => {
    try {
      const res = await axiosInstance.post(adminEndpoints.login, { email, password });
      const { accessToken, user: u } = res.data;
      if (!accessToken) {
        throw parseAdminLoginError(new Error("No token in response"));
      }
      setToken(accessToken);
      setUser({ ...u, role: u?.role ?? "admin" });
    } catch (error) {
      throw parseAdminLoginError(error);
    }
  }, []);

  const logout = useCallback(async () => {
    try {
      await axiosInstance.post(adminEndpoints.logout);
    } catch (_) {}
    setToken(null);
    setUser(null);
  }, []);

  const value: AdminAuthContextValue = {
    user,
    loading,
    authenticated: !!user,
    login,
    logout,
    checkSession,
  };

  return (
    <AdminAuthContext.Provider value={value}>
      {children}
    </AdminAuthContext.Provider>
  );
}

export function useAdminAuth() {
  const ctx = useContext(AdminAuthContext);
  if (!ctx) throw new Error("useAdminAuth must be used within AdminAuthProvider");
  return ctx;
}
