import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
import type { ReactNode } from "react";
import { api, setToken, getToken } from "./api";
import type { Business, User } from "../../shared/types";

interface AuthState {
  user: User | null;
  business: Business | null;
  loading: boolean;
  login: (email: string, password: string) => Promise<void>;
  logout: () => void;
  switchUser: (userId: number, email: string) => Promise<void>;
  refreshBusiness: () => Promise<void>;
}

const Ctx = createContext<AuthState | null>(null);

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null);
  const [business, setBusiness] = useState<Business | null>(null);
  const [loading, setLoading] = useState(true);

  const loadBusiness = useCallback(async (role?: string) => {
    if (role === "admin") return; // admins have no business
    try {
      const { business } = await api.business.get();
      setBusiness(business);
    } catch {
      /* ignore */
    }
  }, []);

  useEffect(() => {
    const t = getToken();
    if (!t) {
      setLoading(false);
      return;
    }
    // Token is the user id; we need the user object. Quick login isn't re-called,
    // so we hydrate by calling /me. Server stores users in db; fetch demo list and match.
    (async () => {
      try {
        const res = await fetch("/api/auth/me", { headers: { authorization: `Bearer ${t}` } });
        if (!res.ok) throw new Error();
        const { user } = (await res.json()) as { user: User };
        setUser(user);
        await loadBusiness(user.role);
      } catch {
        setToken(null);
      } finally {
        setLoading(false);
      }
    })();
  }, [loadBusiness]);

  const login = useCallback(
    async (email: string, password: string) => {
      const { token, user } = await api.auth.login(email, password);
      setToken(token);
      setUser(user);
      await loadBusiness(user.role);
    },
    [loadBusiness]
  );

  const switchUser = useCallback(
    async (userId: number, email: string) => {
      // Quick demo: try logging in with known demo password
      try {
        const { token, user } = await api.auth.login(email, "demo1234");
        setToken(token);
        setUser(user);
        await loadBusiness(user.role);
        void userId;
      } catch (e) {
        throw e;
      }
    },
    [loadBusiness]
  );

  const logout = useCallback(() => {
    setToken(null);
    setUser(null);
    setBusiness(null);
  }, []);

  const value = useMemo(
    () => ({ user, business, loading, login, logout, switchUser, refreshBusiness: loadBusiness }),
    [user, business, loading, login, logout, switchUser, loadBusiness]
  );

  return <Ctx.Provider value={value}>{children}</Ctx.Provider>;
}

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