"use client";

import {
  createContext,
  useContext,
  useState,
  useEffect,
  ReactNode,
} from "react";
import axios from "axios";
import { API_URL, AUTH_ENDPOINTS } from "../constants/config";
import { api } from "../services/api";

interface Role {
  id: number;
  key: string;
  name: string;
}

interface User {
  id: number;
  firstname: string;
  lastname: string;
  email: string;
  roles: Role[];
}

interface AuthContextType {
  user: User | null;
  login: (email: string, password: string) => Promise<void>;
  register: (
    email: string,
    password: string,
    firstname: string,
    lastname: string
  ) => Promise<void>;
  logout: () => void;
  isLoading: boolean;
  hasRole: (roleKey: string) => boolean;
  isAdmin: () => boolean;
  isSupplier: () => boolean;
}

const AuthContext = createContext<AuthContextType | undefined>(undefined);

// Use the shared API instance from services/api.ts instead of creating a new one
const authApi = axios.create({
  baseURL: API_URL,
  headers: {
    "Content-Type": "application/json",
    Accept: "application/json",
  },
  withCredentials: true,
});

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  // Check for token and fetch user data on initial load and when component mounts
  useEffect(() => {
    const loadUserFromToken = async () => {
      setIsLoading(true);
      const token = localStorage.getItem("token");

      if (!token) {
        setIsLoading(false);
        return;
      }

      // Set token in auth headers for both API instances
      authApi.defaults.headers.common["Authorization"] = `Bearer ${token}`;
      api.defaults.headers.common["Authorization"] = `Bearer ${token}`;

      try {
        // Get user data to validate token
        const response = await authApi.get(AUTH_ENDPOINTS.USER);
        setUser(response.data);
      } catch (error) {
        console.error("Failed to fetch user data:", error);

        // Only clear token if it's an authentication error (401)
        if (axios.isAxiosError(error) && error.response?.status === 401) {
          localStorage.removeItem("token");
          setUser(null);
        }
      } finally {
        setIsLoading(false);
      }
    };

    loadUserFromToken();

    // Set up event listener for storage changes (for multi-tab support)
    const handleStorageChange = (e: StorageEvent) => {
      if (e.key === "token") {
        if (e.newValue) {
          loadUserFromToken();
        } else {
          setUser(null);
        }
      }
    };

    window.addEventListener("storage", handleStorageChange);

    return () => {
      window.removeEventListener("storage", handleStorageChange);
    };
  }, []);

  const login = async (email: string, password: string) => {
    try {
      const response = await authApi.post(AUTH_ENDPOINTS.LOGIN, {
        email,
        password,
      });

      const { access_token, user } = response.data;

      // Save token to localStorage
      localStorage.setItem("token", access_token);

      // Update token in both API instances
      authApi.defaults.headers.common[
        "Authorization"
      ] = `Bearer ${access_token}`;
      api.defaults.headers.common["Authorization"] = `Bearer ${access_token}`;

      setUser(user);
    } catch (error) {
      console.error("Login error:", error);
      throw new Error("Login failed");
    }
  };

  const register = async (
    email: string,
    password: string,
    firstname: string,
    lastname: string
  ) => {
    try {
      await authApi.post(AUTH_ENDPOINTS.REGISTER, {
        email,
        password,
        firstname,
        lastname,
      });
      await login(email, password);
    } catch (error) {
      console.error("Registration error:", error);
      throw new Error("Registration failed");
    }
  };

  const logout = () => {
    localStorage.removeItem("token");
    delete authApi.defaults.headers.common["Authorization"];
    delete api.defaults.headers.common["Authorization"];
    setUser(null);
  };

  const hasRole = (roleKey: string): boolean => {
    return user?.roles?.some((role) => role.key === roleKey) || false;
  };

  const isAdmin = (): boolean => {
    return hasRole("admin");
  };

  const isSupplier = (): boolean => {
    return hasRole("supplier");
  };

  return (
    <AuthContext.Provider
      value={{
        user,
        login,
        register,
        logout,
        isLoading,
        hasRole,
        isAdmin,
        isSupplier,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const context = useContext(AuthContext);
  if (context === undefined) {
    throw new Error("useAuth must be used within an AuthProvider");
  }
  return context;
}
