/**
 * Bootstrap helpers: load state from API or show register/connect UI.
 */

import { defaultState, normalizeZooWeights } from "./state.js";
import { refreshOffers, getPlayerZooWeights } from "./conveyor.js";
import { ensureBotState } from "./bot-zoo.js";
import { loadZoos, loadMyZoo, register, createMyZoo } from "./api-client.js";
import { getOrCreateKeyPair } from "./auth-client.js";

/**
 * @param {import("./types.js").GameState} gameState
 * @param {{ zoosData: { worldZoos?: Array<unknown> }, playerZooId?: string, playerName?: string, playerX?: number, playerY?: number }} opts
 * @returns {void}
 */
export function applyWorldZoos(gameState, opts) {
  const { zoosData, playerZooId, playerName, playerX, playerY } = opts;
  const playerWeights = getPlayerZooWeights(gameState);
  const playerEntry = {
    id: "player",
    name: playerName || "Mon zoo",
    x: playerX ?? 25,
    y: playerY ?? 50,
    animalWeights: playerWeights,
  };
  const others = (zoosData.worldZoos || [])
    .filter((z) => z.id !== playerZooId)
    .map((z) => ({
      ...z,
      animalWeights: normalizeZooWeights(z.animalWeights),
      botState: z.game_state ?? undefined,
    }));
  others.forEach((zoo) => ensureBotState(zoo, false));
  gameState.worldZoos = [playerEntry, ...others];
}

/**
 * @returns {Promise<import("./types.js").GameState>}
 */
export function bootstrapNoKeys() {
  const s = defaultState();
  const nowUnix = Math.floor(Date.now() / 1000);
  refreshOffers(s, nowUnix);
  return Promise.resolve(s);
}

/**
 * @param {{ worldZoos?: Array<unknown> }} zoosData
 * @param {HTMLElement} rootEl
 * @param {(zooId: string) => void} setMyZooId
 * @returns {Promise<import("./types.js").GameState>}
 */
export function bootstrapShowRegisterPanel(zoosData, rootEl, setMyZooId) {
  return new Promise((resolve) => {
    rootEl.innerHTML = "<div class=\"boot-panel\"><h1>Construis un zoo</h1><p>Créer un compte (pseudo, pas de mot de passe)</p><input id=\"boot-pseudo\" type=\"text\" placeholder=\"Pseudo\" maxlength=\"32\" /><button id=\"boot-submit\">Créer</button><p id=\"boot-err\" class=\"boot-err\"></p></div>";
    const errEl = document.getElementById("boot-err");
    document.getElementById("boot-submit").addEventListener("click", async () => {
      const pseudo = document.getElementById("boot-pseudo").value.trim();
      if (pseudo.length < 2) {
        errEl.textContent = "Pseudo min. 2 caractères";
        return;
      }
      errEl.textContent = "";
      try {
        await register(pseudo);
        const s = defaultState();
        const nowUnix = Math.floor(Date.now() / 1000);
        refreshOffers(s, nowUnix);
        const created = await createMyZoo(pseudo, s);
        setMyZooId(created.zooId);
        applyWorldZoos(s, { zoosData, playerZooId: created.zooId, playerName: created.name, playerX: created.x, playerY: created.y });
        s.myZooId = created.zooId;
        s.playerName = created.name;
        s.playerX = created.x;
        s.playerY = created.y;
        resolve(s);
      } catch (e) {
        errEl.textContent = e.message || "Erreur";
      }
    });
  });
}

/**
 * @param {{ worldZoos?: Array<unknown> }} zoosData
 * @returns {Promise<import("./types.js").GameState>}
 */
export async function bootstrapMe404(zoosData) {
  const s = defaultState();
  const nowUnix = Math.floor(Date.now() / 1000);
  refreshOffers(s, nowUnix);
  const created = await createMyZoo("Mon zoo", s);
  const myZooId = created.zooId;
  applyWorldZoos(s, { zoosData, playerZooId: myZooId, playerName: created.name, playerX: created.x, playerY: created.y });
  s.myZooId = myZooId;
  s.playerName = created.name;
  s.playerX = created.x;
  s.playerY = created.y;
  return s;
}

/**
 * @param {{ game_state: import("./types.js").GameState; zooId: string; name: string; x: number; y: number }} me
 * @param {{ worldZoos?: Array<unknown> }} zoosData
 * @returns {import("./types.js").GameState}
 */
export function bootstrapMeWithGameState(me, zoosData) {
  const s = me.game_state;
  const myZooId = me.zooId;
  s.myZooId = myZooId;
  s.playerName = me.name;
  s.playerX = me.x;
  s.playerY = me.y;
  if (s.coins < 100) s.coins = 200;
  const nowUnix = Math.floor(Date.now() / 1000);
  if (s.conveyorOffers === null || s.conveyorOffers === undefined || s.conveyorOffers.length === 0) {
    refreshOffers(s, nowUnix);
  }
  applyWorldZoos(s, { zoosData, playerZooId: myZooId, playerName: me.name, playerX: me.x, playerY: me.y });
  return s;
}

/**
 * @param {{ name?: string }} me
 * @param {{ worldZoos?: Array<unknown> }} zoosData
 * @returns {Promise<import("./types.js").GameState>}
 */
export async function bootstrapMeCreateZoo(me, zoosData) {
  const s = defaultState();
  const nowUnix = Math.floor(Date.now() / 1000);
  refreshOffers(s, nowUnix);
  const created = await createMyZoo(me.name || "Mon zoo", s);
  const myZooId = created.zooId;
  applyWorldZoos(s, { zoosData, playerZooId: myZooId, playerName: created.name, playerX: created.x, playerY: created.y });
  s.myZooId = myZooId;
  s.playerName = created.name;
  s.playerX = created.x;
  s.playerY = created.y;
  return s;
}

/**
 * @param {(zooId: string) => void} setMyZooId
 * @param {HTMLElement} rootEl
 * @returns {Promise<import("./types.js").GameState>}
 */
export async function bootstrapFromApi(setMyZooId, rootEl) {
  const keys = await getOrCreateKeyPair();
  if (!keys) {
    return bootstrapNoKeys();
  }
  let zoosData = { worldZoos: [], mapWidth: 100, mapHeight: 100 };
  try {
    zoosData = await loadZoos();
  } catch (e) {
    console.warn("loadZoos failed", e);
  }
  const meRes = await loadMyZoo().catch((e) => {
    console.warn("loadMyZoo failed", e);
    return { status: 401 };
  });
  if (meRes.status === 401) {
    return bootstrapShowRegisterPanel(zoosData, rootEl, setMyZooId);
  }
  if (meRes.status === 404) {
    const s = await bootstrapMe404(zoosData);
    setMyZooId(s.myZooId ?? "player");
    return s;
  }
  const me = meRes.data;
  if (me.game_state && typeof me.game_state === "object") {
    setMyZooId(me.zooId);
    return bootstrapMeWithGameState(me, zoosData);
  }
  const s = await bootstrapMeCreateZoo(me, zoosData);
  setMyZooId(s.myZooId ?? "player");
  return s;
}
