import { tryUpgradeWorldMap, tryUpgradePlot } from "./zoo.js";
import { tryUpgradeTruck } from "./conveyor.js";
import { getTruckUpgradeCost } from "./economy.js";
import { playSound } from "./audio.js";
import { t, errorMessage, sellZoneTitle, sellZoneShortLabel } from "./texts-fr.js";
import { GameConfig } from "./config.js";
import { handleWorldMapTruckDrop, handleSellZoneDrop } from "./ui-render-dom-drops.js";

/**
 * @param {HTMLElement} panelWorld
 * @param {{ state: import("./types.js").GameState }} setup
 * @returns {{ worldMapEl: HTMLElement, worldMapTruckEl: HTMLElement, worldMapNpcTrucksEl: HTMLElement }}
 */
function buildWorldMapWrap(panelWorld, setup) {
  const { state } = setup;
  const worldMapWrap = document.createElement("div");
  worldMapWrap.className = "world-map-wrap world-map-wrap-square";
  const worldMapEl = document.createElement("div");
  worldMapEl.className = "world-map world-map-biomes";
  const mapLevel = state.worldMapLevel ?? 1;
  const zoom = Math.min(0.65 + (mapLevel - 1) * 0.2, 1.45);
  worldMapEl.style.transformOrigin = "50% 50%";
  worldMapEl.style.transform = `scale(${zoom})`;
  worldMapWrap.appendChild(worldMapEl);
  const worldMapTruckEl = document.createElement("div");
  worldMapTruckEl.className = "world-map-truck";
  worldMapTruckEl.setAttribute("aria-hidden", "true");
  worldMapWrap.appendChild(worldMapTruckEl);
  const worldMapNpcTrucksEl = document.createElement("div");
  worldMapNpcTrucksEl.className = "world-map-trucks";
  worldMapNpcTrucksEl.setAttribute("aria-hidden", "true");
  worldMapWrap.appendChild(worldMapNpcTrucksEl);
  panelWorld.appendChild(worldMapWrap);
  return { worldMapEl, worldMapTruckEl, worldMapNpcTrucksEl };
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
 * @returns {HTMLElement}
 */
function buildWorldMapUpgradeZone(setup) {
  const { state, setState, setError } = setup;
  const worldMapUpgradeZone = document.createElement("div");
  worldMapUpgradeZone.className = "world-map-upgrade-zone";
  worldMapUpgradeZone.setAttribute("aria-label", "Agrandir la carte");
  worldMapUpgradeZone.title = "Agrandir la carte";
  worldMapUpgradeZone.innerHTML = "<span class=\"world-map-upgrade-zone-icon\" aria-hidden=\"true\">🗺️</span><span class=\"world-map-upgrade-zone-label\">Agrandir carte</span><span class=\"world-map-upgrade-zone-cost\" aria-hidden=\"true\"></span><span class=\"world-map-upgrade-zone-arrow\" aria-hidden=\"true\">▲</span>";
  worldMapUpgradeZone.setAttribute("role", "button");
  worldMapUpgradeZone.setAttribute("tabindex", "0");
  worldMapUpgradeZone.addEventListener("click", () => {
    const [ok, reason] = tryUpgradeWorldMap(state);
    if (!ok) {
      setError(String(t.upgradeWorldMapFailed).replace("%s", errorMessage[reason] ?? reason));
      playSound("error");
    } else {
      setError("");
      playSound("worldMapUpgrade");
    }
    setState();
  });
  worldMapUpgradeZone.addEventListener("keydown", (e) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      worldMapUpgradeZone.click();
    }
  });
  return worldMapUpgradeZone;
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
 * @returns {HTMLElement}
 */
function buildWorldMapTruckDropZone(setup) {
  const worldMapTruckDropZone = document.createElement("div");
  worldMapTruckDropZone.className = "world-map-truck-drop-zone";
  worldMapTruckDropZone.setAttribute("aria-label", "Camion pour acheter un œuf");
  worldMapTruckDropZone.title = "Glissez un œuf ici pour l'acheter";
  worldMapTruckDropZone.innerHTML = "<span class=\"world-map-truck-drop-icon\" aria-hidden=\"true\">🚚</span><span class=\"world-map-truck-drop-label\">Acheter œuf</span>";
  worldMapTruckDropZone.addEventListener("dragover", (e) => {
    e.preventDefault();
    const hasOffer = e.dataTransfer.types.includes("application/x-builazoo-eggtype")
      || e.dataTransfer.types.includes("application/x-builazoo-baby-offer")
      || e.dataTransfer.types.includes("application/x-builazoo-animal-offer");
    e.dataTransfer.dropEffect = hasOffer ? "copy" : "none";
    if (hasOffer) worldMapTruckDropZone.classList.add("dragover");
  });
  worldMapTruckDropZone.addEventListener("dragleave", () => worldMapTruckDropZone.classList.remove("dragover"));
  worldMapTruckDropZone.addEventListener("drop", (ev) => handleWorldMapTruckDrop(ev, setup));
  return worldMapTruckDropZone;
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
 * @returns {{ worldMapUpgradeZone: HTMLElement, worldMapCounters: HTMLElement, worldMapTruckDropZone: HTMLElement, worldMapActions: HTMLElement }}
 */
function buildWorldMapActions(setup) {
  const worldMapActions = document.createElement("div");
  worldMapActions.className = "world-map-actions";
  const worldMapUpgradeZone = buildWorldMapUpgradeZone(setup);
  worldMapActions.appendChild(worldMapUpgradeZone);
  const worldMapCounters = document.createElement("div");
  worldMapCounters.className = "world-map-counters";
  worldMapCounters.setAttribute("aria-label", "Compteurs carte du monde");
  worldMapActions.appendChild(worldMapCounters);
  const worldMapTruckDropZone = buildWorldMapTruckDropZone(setup);
  worldMapActions.appendChild(worldMapTruckDropZone);
  return { worldMapUpgradeZone, worldMapCounters, worldMapTruckDropZone, worldMapActions };
}

/**
 * @param {HTMLElement} panelWorld
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void }} setup
 * @returns {{ worldMapEl: HTMLElement, worldMapTruckEl: HTMLElement, worldMapNpcTrucksEl: HTMLElement, worldMapUpgradeZone: HTMLElement, worldMapCounters: HTMLElement }}
 */
export function buildWorldMapSection(panelWorld, setup) {
  const wrapResult = buildWorldMapWrap(panelWorld, setup);
  const actionsResult = buildWorldMapActions(setup);
  panelWorld.appendChild(actionsResult.worldMapActions);
  return { ...wrapResult, worldMapUpgradeZone: actionsResult.worldMapUpgradeZone, worldMapCounters: actionsResult.worldMapCounters };
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void }} setup
 * @returns {HTMLElement}
 */
function buildPlotUpgradeZone(setup) {
  const { state, setState, setError } = setup;
  const plotUpgradeZone = document.createElement("div");
  plotUpgradeZone.className = "plot-upgrade-zone";
  plotUpgradeZone.setAttribute("aria-label", t.upgradePlot);
  plotUpgradeZone.title = t.upgradePlot;
  plotUpgradeZone.innerHTML = "<span class=\"plot-upgrade-zone-icon\" aria-hidden=\"true\">📐</span><span class=\"plot-upgrade-zone-label\">Agrandir zoo</span><span class=\"plot-upgrade-zone-arrow\" aria-hidden=\"true\">▲</span>";
  plotUpgradeZone.setAttribute("role", "button");
  plotUpgradeZone.setAttribute("tabindex", "0");
  plotUpgradeZone.addEventListener("click", () => {
    const [ok, reason] = tryUpgradePlot(state);
    if (!ok) {
      setError(String(t.upgradePlotFailed).replace("%s", errorMessage[reason] ?? reason));
      playSound("error");
    } else {
      setError("");
      playSound("plotUpgrade");
    }
    setState();
  });
  plotUpgradeZone.addEventListener("keydown", (e) => {
    if (e.key === "Enter" || e.key === " ") {
      e.preventDefault();
      plotUpgradeZone.click();
    }
  });
  return plotUpgradeZone;
}

/**
 * @param {HTMLElement} panelZoo
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDropRef: { current: boolean }, sellZoneJustDroppedRef: { current: boolean } }} setup
 * @returns {{ gridEl: HTMLElement, plotUpgradeZone: HTMLElement, sellZone: HTMLElement }}
 */
export function buildGridSection(panelZoo, setup) {
  const gridWrap = document.createElement("div");
  gridWrap.className = "grid-wrap";
  const gridEl = document.createElement("div");
  gridEl.className = "grid";
  gridWrap.appendChild(gridEl);
  const plotUpgradeZone = buildPlotUpgradeZone(setup);
  gridWrap.appendChild(plotUpgradeZone);
  const sellZone = document.createElement("div");
  sellZone.className = "sell-zone";
  sellZone.setAttribute("aria-label", sellZoneTitle);
  sellZone.title = sellZoneTitle;
  sellZone.innerHTML = "<span class=\"sell-zone-icon\" aria-hidden=\"true\">🚚</span><span class=\"sell-zone-label\">" + sellZoneShortLabel + "</span><span class=\"sell-zone-upgrade-arrow\" aria-hidden=\"true\">▲</span>";
  attachSellZoneListeners(sellZone, setup);
  gridWrap.appendChild(sellZone);
  const visitorsLayer = document.createElement("div");
  visitorsLayer.className = "visitors-layer";
  visitorsLayer.setAttribute("aria-hidden", "true");
  gridWrap.appendChild(visitorsLayer);
  panelZoo.appendChild(gridWrap);
  return { gridEl, plotUpgradeZone, sellZone };
}

/**
 * @param {HTMLElement} sellZone
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDropRef: { current: boolean }, sellZoneJustDroppedRef: { current: boolean } }} setup
 * @returns {void}
 */
function attachSellZoneListeners(sellZone, setup) {
  sellZone.addEventListener("dragover", (e) => {
    e.preventDefault();
    const hasCell = e.dataTransfer.types.includes("text/plain");
    e.dataTransfer.dropEffect = hasCell ? "move" : "none";
    if (hasCell) sellZone.classList.add("dragover");
  });
  sellZone.addEventListener("dragleave", () => sellZone.classList.remove("dragover"));
  sellZone.addEventListener("drop", (e) => handleSellZoneDrop(e, setup));
  sellZone.addEventListener("click", () => handleSellZoneClick(setup));
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, sellZoneJustDroppedRef: { current: boolean } }} setup
 * @returns {void}
 */
function handleSellZoneClick(setup) {
  if (setup.sellZoneJustDroppedRef.current) {
    setup.sellZoneJustDroppedRef.current = false;
    return;
  }
  const state = setup.state;
  const truckLevel = state.truckLevel ?? 1;
  const truckMax = (GameConfig.Truck && GameConfig.Truck.MaxLevel) || 5;
  if (truckLevel >= truckMax) return;
  if (state.coins < getTruckUpgradeCost(truckLevel)) return;
  const [ok, reason] = tryUpgradeTruck(state);
  if (!ok) {
    setup.setError(String(t.upgradeConveyorFailed).replace("%s", errorMessage[reason] ?? reason));
    playSound("error");
  } else {
    setup.setError("");
    playSound("truckUpgrade");
  }
  setup.setState();
}
