import type { ReactNode } from "react";
import { createContext, useContext, useState, useEffect, useRef } from "react";

import { apiAccountLogoutCreate } from "@/api/generated/public/account";
import { apiAccountUserMeRetrieve } from "@/api/generated/private/account/account";
import { privateApi } from "@/api/privateClient";

import type { CustomTokenObtainPair } from "@/api/generated/public/models/customTokenObtainPair";
import type { CustomUser } from "@/api/generated/private/models/customUser";

export const AUTH_FLAG = "vontor_was_logged_in";

interface AuthContextType {
  user: CustomUser | null;
  isAuthenticated: boolean;
  isLoading: boolean;
  login: (payload: CustomTokenObtainPair) => Promise<void>;
  logout: () => Promise<void>;
  refreshUser: () => Promise<void>;
}

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

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

  const isAuthenticated = !!user;

  async function refreshUser() {
    const wasLoggedIn = localStorage.getItem(AUTH_FLAG);

    if (!wasLoggedIn) {
      setUser(null);
      setIsLoading(false);
      return;
    }

    try {
      const userData = await apiAccountUserMeRetrieve();
      setUser(userData);
    } catch {
      setUser(null);
      localStorage.removeItem(AUTH_FLAG);
    } finally {
      setIsLoading(false);
    }
  }

  useEffect(() => {
    if (!initialized.current) {
      initialized.current = true;
      refreshUser();
    }
  }, []);

  async function login(payload: CustomTokenObtainPair) {
    setIsLoading(true);
    try {
      await privateApi.post("/api/account/login/", payload);
      localStorage.setItem(AUTH_FLAG, "true");
      await refreshUser();
    } catch (err: any) {
      setIsLoading(false);
      const data = err.response?.data;
      const errorMessage =
        data?.detail ||
        (typeof data === "object" && !Array.isArray(data)
          ? Object.values(data).flat().filter(Boolean).join(" ")
          : null) ||
        err.message ||
        "Login failed";
      throw new Error(errorMessage);
    }
  }

  async function logout() {
    setIsLoading(true);
    try {
      localStorage.removeItem(AUTH_FLAG);
      await apiAccountLogoutCreate();
    } catch (err: any) {
      console.error("Logout error:", err);
    } finally {
      setUser(null);
      setIsLoading(false);
    }
  }

  return (
    <AuthContext.Provider value={{ user, isAuthenticated, isLoading, login, logout, refreshUser }}>
      {children}
    </AuthContext.Provider>
  );
}

export function useAuth() {
  const ctx = useContext(AuthContext);
  if (!ctx) throw new Error("useAuth must be used inside AuthProvider");
  return ctx;
}
