import React, { createContext, useContext, useEffect, useState } from "react";
import { tokenStore } from "./token";
import { createApiClient } from "./axios";
import { AuthUser } from "./models";

export interface AuthServerConfig {
  serverUrl: string;
  loginPath: string;
  registerPath: string;
  logoutPath: string;
  mePath: string;
  introspectPath: string;
}

interface AuthContextModel {
  currentUser: AuthUser | null;
  token: string | null;
  loading: boolean;
  error: string | null;
  login(username: string, password: string): Promise<void>;
  register(username: string, password: string): Promise<void>;
  logout(): void;
}

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

export function AuthProvider({
  children,
  authConfig,
  onUnauthorized,
}: {
  children: React.ReactNode;
  authConfig: AuthServerConfig;
  onUnauthorized?: () => void;
}) {
  const [currentUser, setCurrentUser] = useState<AuthUser | null>(null);
  const [token, setToken] = useState<string | null>(tokenStore.get());
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const auth = createApiClient(authConfig.serverUrl);

  const login = async (username: string, password: string) => {
    try {
      setLoading(true);
      setError(null);

      const res = await auth.post(authConfig.loginPath, { username, password });
      const { access_token, user } = res.data;

      tokenStore.set(access_token);
      setToken(access_token);
      setCurrentUser(user);
    } catch (e: any) {
      setError(e.response?.data?.detail ?? "Login failed");
    } finally {
      setLoading(false);
    }
  };

  const register = async (username: string, password: string) => {
    try {
      setLoading(true);
      setError(null);

      await auth.post(authConfig.registerPath, { username, password });
      await login(username, password);
    } catch (e: any) {
      setError(e.response?.data?.detail ?? "Registration failed");
    } finally {
      setLoading(false);
    }
  };

  const logout = async () => {
    try {
      await auth.post(authConfig.logoutPath);
    } catch {
      // Server logout is best-effort; clear token locally regardless
    }
    tokenStore.clear();
    setToken(null);
    setCurrentUser(null);
  };

  const fetchCurrentUser = async () => {
    if (!token) { console.log("[AuthProvider] fetchCurrentUser SKIP no token"); return; }
    console.log("[AuthProvider] fetchCurrentUser calling %s%s", authConfig.serverUrl, authConfig.mePath);
    try {
      const me = await auth.get(authConfig.mePath);
      console.log("[AuthProvider] fetchCurrentUser SUCCESS", me.data);
      setCurrentUser({ ...me.data });
    } catch (e: any) {
      console.log("[AuthProvider] fetchCurrentUser ERROR", e.message, e.response?.status);
      tokenStore.clear();
      setToken(null);
      setCurrentUser(null);
      onUnauthorized?.();
    }
  };

  useEffect(() => {
    console.log("[AuthProvider] useEffect token=%s serverUrl=%s", token, authConfig.serverUrl);
    if (authConfig.serverUrl) {
      fetchCurrentUser();
    }
  }, [token, authConfig.serverUrl]);

  useEffect(() => {
    const handler = () => {
      console.log("[AuthProvider] auth:unauthorized event received");
      tokenStore.clear();
      setToken(null);
      setCurrentUser(null);
      onUnauthorized?.();
    };
    console.log("[AuthProvider] adding auth:unauthorized listener");
    window.addEventListener("auth:unauthorized", handler);
    return () => {
      console.log("[AuthProvider] removing auth:unauthorized listener");
      window.removeEventListener("auth:unauthorized", handler);
    };
  }, [onUnauthorized]);

  return (
    <AuthContext.Provider
      value={{ currentUser, token, loading, error, login, logout, register }}
    >
      {children}
    </AuthContext.Provider>
  );
}

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