/**
 * Drag-related helpers for grid cells: set DataTransfer for dragstart, attach drag listeners, handle drop.
 */
import { tryBuyEgg, tryPlaceEgg, placeMatureBabyOnCell, placeReceptionAnimalOnCell } from "./zoo.js";
import { moveCell } from "./placement.js";
import { t, errorMessage } from "./texts-fr.js";

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDrop: { current: boolean } }} ctx
 * @param {DragEvent} e
 * @param {{ x: number, y: number, empty: boolean }} target
 * @returns {boolean}
 */
export function handleCellDropNurseryReceptionToken(ctx, e, target) {
  const { state, setState, setError, playSound } = ctx;
  const { x: toX, y: toY, empty } = target;
  const nurseryCellKey = e.dataTransfer.getData("application/x-builazoo-nursery-cell-key");
  if (nurseryCellKey && empty) {
    const nowUnix = Math.floor(Date.now() / 1000);
    const [ok, reason] = placeMatureBabyOnCell(state, { nurseryCellKey, toX, toY, nowUnix });
    if (ok) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
    ctx.lastActionWasDrop.current = true;
    setState();
    return true;
  }
  const receptionCellKey = e.dataTransfer.getData("application/x-builazoo-reception-cell-key");
  if (receptionCellKey && empty) {
    const nowUnix = Math.floor(Date.now() / 1000);
    const [ok, reason] = placeReceptionAnimalOnCell(state, { receptionCellKey, toX, toY, nowUnix });
    if (ok) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); playSound("error"); }
    ctx.lastActionWasDrop.current = true;
    setState();
    return true;
  }
  const tokenIdStr = e.dataTransfer.getData("application/x-builazoo-tokenid");
  if (tokenIdStr && empty) {
    const tokenId = Number(tokenIdStr);
    if (!Number.isNaN(tokenId)) {
      const nowUnix = Math.floor(Date.now() / 1000);
      const [placeOk, placeReason] = tryPlaceEgg(state, { tokenId, x: toX, y: toY, nowUnix });
      if (placeOk) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[placeReason] ?? placeReason)); playSound("error"); }
      ctx.lastActionWasDrop.current = true;
      setState();
    }
    return true;
  }
  return false;
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, lastActionWasDrop: { current: boolean } }} ctx
 * @param {DragEvent} e
 * @param {{ x: number, y: number, empty: boolean }} target
 * @returns {boolean}
 */
export function handleCellDropEggTypeOrMove(ctx, e, target) {
  const { state, setState, setError, playSound } = ctx;
  const { x: toX, y: toY, empty } = target;
  const eggTypeFromConveyor = e.dataTransfer.getData("application/x-builazoo-eggtype");
  if (eggTypeFromConveyor && empty) {
    const [buyOk, buyResult] = tryBuyEgg(state, eggTypeFromConveyor);
    if (!buyOk) { setError(String(t.buyFailed).replace("%s", errorMessage[buyResult] ?? buyResult)); playSound("error"); } else {
      const tokenId = buyResult.tokenId;
      const nowUnix = Math.floor(Date.now() / 1000);
      const [placeOk, placeReason] = tryPlaceEgg(state, { tokenId, x: toX, y: toY, nowUnix });
      if (placeOk) { setError(""); playSound("place"); } else { setError(String(t.errorPrefix).replace("%s", errorMessage[placeReason] ?? placeReason)); playSound("error"); }
    }
    ctx.lastActionWasDrop.current = true;
    setState();
    return true;
  }
  const raw = e.dataTransfer.getData("text/plain");
  if (!raw || !/^\d+_\d+$/.test(raw)) return true;
  const [sx, sy] = raw.split("_").map(Number);
  const [ok, reason] = moveCell(state, { fromX: sx, fromY: sy, toX, toY });
  if (!ok) setError(String(t.errorPrefix).replace("%s", errorMessage[reason] ?? reason)); else setError("");
  ctx.lastActionWasDrop.current = true;
  setState();
  return true;
}

/**
 * @param {HTMLElement} div
 * @param {import("./types.js").GridCell | null | undefined} cell
 * @param {{ x: number, y: number }} pos
 * @param {DataTransfer} dt
 */
export function setCellDragData(div, cell, pos, dt) {
  const { x, y } = pos;
  let dragX = x;
  let dragY = y;
  if (div.dataset.nurseryCellKey) {
    dt.setData("application/x-builazoo-nursery-cell-key", div.dataset.nurseryCellKey);
    dt.effectAllowed = "move";
  } else if (div.dataset.receptionCellKey) {
    dt.setData("application/x-builazoo-reception-cell-key", div.dataset.receptionCellKey);
    dt.effectAllowed = "move";
  } else if (cell && cell.kind === "animal" && cell.originKey !== null && cell.originKey !== undefined) {
    const m = cell.originKey.match(/^(\d+)_(\d+)$/);
    if (m) { dragX = Number(m[1]); dragY = Number(m[2]); }
  }
  if (!div.dataset.nurseryCellKey && !div.dataset.receptionCellKey) dt.setData("text/plain", `${dragX}_${dragY}`);
  if (cell && cell.kind === "nursery" && cell.tokenId !== null && cell.tokenId !== undefined) {
    dt.setData("application/x-builazoo-tokenid", String(cell.tokenId));
  }
  dt.effectAllowed = dt.effectAllowed || "move";
}

/**
 * @param {{ state: import("./types.js").GameState, setState: () => void, setError: (s: string) => void, playSound: (s: string) => void, gridEl: HTMLElement }} ctx
 * @param {{ div: HTMLElement, cell: import("./types.js").GridCell | null | undefined, x: number, y: number, key: string }} opts
 */
export function attachDragListeners(ctx, opts) {
  const { div, cell } = opts;
  const { gridEl } = ctx;
  const isDraggable = cell !== null && cell !== undefined && (
    cell.kind === "egg" || cell.kind === "animal" ||
    (cell.kind === "nursery" && (cell.tokenId !== null && cell.tokenId !== undefined || div.dataset.nurseryCellKey)) ||
    (cell.kind === "reception" && div.dataset.receptionCellKey)
  );
  if (!isDraggable) return;
  div.addEventListener("dragstart", (e) => {
    setCellDragData(div, cell, { x: opts.x, y: opts.y }, e.dataTransfer);
    div.classList.add("dragging");
    const ghost = div.cloneNode(true);
    ghost.classList.add("drag-ghost");
    ghost.style.opacity = "1";
    document.body.appendChild(ghost);
    e.dataTransfer.setDragImage(ghost, 24, 24);
    div.addEventListener("dragend", () => { ghost.remove(); }, { once: true });
  });
  div.addEventListener("dragend", () => {
    div.classList.remove("dragging");
    gridEl.querySelectorAll(".cell").forEach((c) => c.classList.remove("dragover"));
  });
}
