import { create } from "zustand";
import { signInWithCustomToken, signOut as firebaseSignOut } from "firebase/auth";
import { apiClient } from "@/api/client";
import type { Human } from "@/api/types";
import { firebaseAuth } from "@/firebase";
import { logError, ApiError } from "@/lib/errors";
import { useSessionStore } from "./session-store";

async function signInToFirebase() {
  try {
    const { token } = await apiClient.getFirebaseToken();
    await signInWithCustomToken(firebaseAuth, token);
  } catch (err) {
    // Firestore subscriptions will fail until the next successful sign-in; the
    // rest of the app keeps working against Orion.
    logError(err, { scope: "auth.firebase" });
  }
}

type AuthStatus = "idle" | "restoring" | "unauthenticated" | "authenticated";

interface AuthState {
  status: AuthStatus;
  user: Human | null;
  isRequestingCode: boolean;
  isSigningIn: boolean;
  isSigningOut: boolean;
  error: string | null;
  restoreSession: () => Promise<void>;
  requestCode: (email: string) => Promise<void>;
  signIn: (email: string, code: string) => Promise<void>;
  signOut: () => Promise<void>;
  clearError: () => void;
}

export const useAuthStore = create<AuthState>((set) => ({
  status: "idle",
  user: null,
  isRequestingCode: false,
  isSigningIn: false,
  isSigningOut: false,
  error: null,

  restoreSession: async () => {
    const token = useSessionStore.getState().token;
    if (!token) {
      set({ status: "unauthenticated" });
      return;
    }

    set({ status: "restoring" });
    try {
      const user = await apiClient.me();
      await signInToFirebase();
      set({ status: "authenticated", user });
    } catch (err) {
      // Expected on expired/invalid tokens — fall back to the login screen.
      logError(err, { scope: "auth.restore" });
      useSessionStore.getState().clearToken();
      set({ status: "unauthenticated", user: null });
    }
  },

  requestCode: async (email: string) => {
    set({ isRequestingCode: true, error: null });
    try {
      await apiClient.requestCode({ email });
    } catch (e) {
      const message =
        e instanceof ApiError ? e.message : "Failed to send code";
      set({ error: message });
      throw e;
    } finally {
      set({ isRequestingCode: false });
    }
  },

  signIn: async (email: string, code: string) => {
    set({ isSigningIn: true, error: null });
    try {
      const { human, token } = await apiClient.signIn({ email, code });
      useSessionStore.getState().setToken(token);
      await signInToFirebase();
      set({ status: "authenticated", user: human });
    } catch (e) {
      const message =
        e instanceof ApiError ? e.message : "Failed to sign in";
      set({ error: message });
      throw e;
    } finally {
      set({ isSigningIn: false });
    }
  },

  signOut: async () => {
    set({ isSigningOut: true });
    try {
      await apiClient.signOut();
    } catch (err) {
      // Best-effort — sign out locally regardless.
      logError(err, { scope: "auth.signOut" });
    } finally {
      await firebaseSignOut(firebaseAuth).catch((err) =>
        logError(err, { scope: "auth.firebaseSignOut" }),
      );
      useSessionStore.getState().clearToken();
      set({
        status: "unauthenticated",
        user: null,
        isSigningOut: false,
        error: null,
      });
    }
  },

  clearError: () => set({ error: null }),
}));

// React to token being cleared externally (e.g. 401 from API client)
useSessionStore.subscribe((state, prevState) => {
  if (prevState.token && !state.token) {
    const authState = useAuthStore.getState();
    if (authState.status === "authenticated") {
      useAuthStore.setState({
        status: "unauthenticated",
        user: null,
        error: null,
      });
    }
  }
});
