import { create } from "zustand";
import { Profile } from "../types";
import { db } from "../database/db";
import { generateId } from "../utils/id";

interface ProfileState {
  activeProfileId: string | null;
  activeProfile: Profile | null;
  profiles: Profile[];
  loadProfiles: () => Promise<void>;
  switchProfile: (id: string) => Promise<void>;
  createProfile: (name: string, avatar?: string) => Promise<Profile>;
  updateProfile: (
    id: string,
    changes: Partial<Pick<Profile, "name" | "avatar">>,
  ) => Promise<void>;
  deleteProfile: (id: string) => Promise<void>;
}

async function ensureDefaultProfile(): Promise<Profile> {
  const now = Date.now();
  const profile: Profile = {
    id: generateId(),
    name: "Moi",
    createdAt: now,
    updatedAt: now,
  };
  await db.profiles.add(profile);
  return profile;
}

async function setActiveProfileId(id: string) {
  const settings = await db.settings.get(1);
  if (settings) {
    await db.settings.put({ ...settings, activeProfileId: id });
  } else {
    await db.settings.add({
      id: 1,
      theme: "system",
      language: "fr",
      activeProfileId: id,
    });
  }
}

export const useProfileStore = create<ProfileState>((set, get) => ({
  activeProfileId: null,
  activeProfile: null,
  profiles: [],

  loadProfiles: async () => {
    let profiles = await db.profiles.orderBy("createdAt").toArray();

    // Defensive: guarantee at least one profile exists
    if (profiles.length === 0) {
      const created = await ensureDefaultProfile();
      profiles = [created];
    }

    const settings = await db.settings.get(1);
    let activeId = settings?.activeProfileId;

    // Fallback if the stored active profile no longer exists
    if (!activeId || !profiles.some((p) => p.id === activeId)) {
      activeId = profiles[0].id;
      await setActiveProfileId(activeId);
    }

    const activeProfile = profiles.find((p) => p.id === activeId) || null;
    set({ profiles, activeProfileId: activeId, activeProfile });
  },

  switchProfile: async (id) => {
    const profile = await db.profiles.get(id);
    if (!profile) return;
    await setActiveProfileId(id);
    set({ activeProfileId: id, activeProfile: profile });
  },

  createProfile: async (name, avatar) => {
    const now = Date.now();
    const profile: Profile = {
      id: generateId(),
      name: name.trim(),
      avatar,
      createdAt: now,
      updatedAt: now,
    };
    await db.profiles.add(profile);
    await get().loadProfiles();
    return profile;
  },

  updateProfile: async (id, changes) => {
    await db.profiles.update(id, { ...changes, updatedAt: Date.now() });
    await get().loadProfiles();
  },

  deleteProfile: async (id) => {
    const { profiles, activeProfileId } = get();

    // Never delete the last remaining profile
    if (profiles.length <= 1) return;

    // Remove this profile and its local data from the device. This is a local
    // removal (not a sync deletion), so we hard-delete without tombstones.
    await db.transaction(
      "rw",
      db.profiles,
      db.sessions,
      db.players,
      db.locations,
      db.syncState,
      async () => {
        await db.sessions.where("profileId").equals(id).delete();
        await db.players.where("profileId").equals(id).delete();
        await db.locations.where("profileId").equals(id).delete();
        await db.syncState.delete(id);
        await db.profiles.delete(id);
      },
    );

    // If we removed the active profile, switch to another one
    if (activeProfileId === id) {
      const remaining = await db.profiles.orderBy("createdAt").first();
      if (remaining) {
        await setActiveProfileId(remaining.id);
      }
    }

    await get().loadProfiles();
  },
}));
