import { create } from "zustand";
import {
  apiJson,
  setAccessToken,
  setOnUnauthorized,
} from "../lib/apiClient";
import { useProfileStore } from "./profileStore";
import { db } from "../database/db";
import { runSync } from "../sync/syncEngine";

export interface AuthUser {
  id: string;
  email: string;
  username: string | null;
  displayName: string;
  avatarUrl: string | null;
}

type AuthStatus = "unknown" | "authenticated" | "anonymous";

interface AuthResponse {
  user: AuthUser;
  accessToken: string;
}

interface AuthState {
  user: AuthUser | null;
  status: AuthStatus;
  register: (input: {
    email: string;
    password: string;
    displayName?: string;
    username?: string;
  }) => Promise<void>;
  login: (email: string, password: string) => Promise<void>;
  logout: () => Promise<void>;
  restore: () => Promise<void>;
  updateAccount: (changes: {
    username?: string;
    displayName?: string;
    avatarUrl?: string | null;
  }) => Promise<void>;
}

async function linkActiveProfileToUser(userId: string) {
  const profileId = useProfileStore.getState().activeProfileId;
  if (profileId) {
    await db.profiles.update(profileId, { remoteUserId: userId });
    await useProfileStore.getState().loadProfiles();
  }
}

export const useAuthStore = create<AuthState>((set) => ({
  user: null,
  status: "unknown",

  register: async ({ email, password, displayName, username }) => {
    const profile = useProfileStore.getState().activeProfile;
    const res = await apiJson<AuthResponse>(
      "/auth/register",
      {
        method: "POST",
        body: JSON.stringify({
          email,
          password,
          displayName: displayName || profile?.name || email,
          username: username || undefined,
          desiredId: profile?.id,
        }),
      },
      { auth: false },
    );
    setAccessToken(res.accessToken);
    set({ user: res.user, status: "authenticated" });
    await linkActiveProfileToUser(res.user.id);
    void runSync();
  },

  login: async (email, password) => {
    const res = await apiJson<AuthResponse>(
      "/auth/login",
      { method: "POST", body: JSON.stringify({ email, password }) },
      { auth: false },
    );
    setAccessToken(res.accessToken);
    set({ user: res.user, status: "authenticated" });
    await linkActiveProfileToUser(res.user.id);
    void runSync();
  },

  logout: async () => {
    try {
      await apiJson("/auth/logout", { method: "POST" }, { auth: false });
    } catch {
      /* ignore network errors on logout */
    }
    setAccessToken(null);
    set({ user: null, status: "anonymous" });
  },

  updateAccount: async (changes) => {
    const res = await apiJson<{ user: AuthUser }>("/me", {
      method: "PATCH",
      body: JSON.stringify(changes),
    });
    set({ user: res.user });
  },

  // On boot: try to silently resume a session via the refresh cookie.
  restore: async () => {
    try {
      const res = await apiJson<AuthResponse>(
        "/auth/refresh",
        { method: "POST" },
        { auth: false },
      );
      setAccessToken(res.accessToken);
      set({ user: res.user, status: "authenticated" });
      void runSync();
    } catch {
      set({ user: null, status: "anonymous" });
    }
  },
}));

// If a refresh ultimately fails mid-request, drop back to anonymous.
setOnUnauthorized(() => {
  setAccessToken(null);
  useAuthStore.setState({ user: null, status: "anonymous" });
});
