import { LootTables } from "./loot-tables.js";
import { getIncomeMultiplier } from "./mutation-rules.js";
import { getSellValue } from "./economy.js";
import { cellKey } from "./grid-utils.js";
import { getBlockKeysFromCell } from "./placement.js";
import { GameConfig } from "./config.js";
import { getReproductionScore } from "./reproduction.js";

/**
 * Default duration and price for a new sale listing from config.
 * @returns {{ duration: number, price: number }}
 */
function getSaleListingDefaults() {
  return {
    duration: GameConfig.Sale?.ListingDurationSeconds ?? 3600,
    price: GameConfig.Sale?.DefaultPrice ?? 50,
  };
}

/**
 * Put a mature baby from nursery on sale (phase 10). Removes it from pendingBabies and clears the nursery cell.
 * @param {import("./types.js").GameState} state
 * @param {string} nurseryCellKey
 * @returns {[boolean, string]} [ok, listingId or reason]
 */
export function addMatureBabyToSale(state, nurseryCellKey) {
  const now = Math.floor(Date.now() / 1000);
  const pendingBabies = state.pendingBabies ?? [];
  const idx = pendingBabies.findIndex(
    (p) => p.nurseryCellKey === nurseryCellKey && now >= p.readyAt
  );
  if (idx < 0) {
    const first = pendingBabies.find((p) => p.nurseryCellKey === nurseryCellKey);
    return [false, first ? "BabyNotMature" : "NoBabyInNursery"];
  }
  const baby = pendingBabies[idx];
  state.pendingBabies = pendingBabies.filter((_, i) => i !== idx);
  const cell = state.grid.cells[nurseryCellKey];
  if (cell && cell.kind === "nursery") cell.tokenId = undefined;
  state.saleListings = state.saleListings ?? [];
  const { duration, price } = getSaleListingDefaults();
  const listingId = `sale_${state.nextTokenId}`;
  state.nextTokenId += 1;
  state.saleListings.push({
    id: listingId,
    zooId: state.myZooId ?? "player",
    animalId: baby.animalId,
    isBaby: true,
    price,
    endAt: now + duration,
    reproductionScoreAtSale: getReproductionScore(state),
  });
  state.lastEvolutionAt = now;
  return [true, listingId];
}

/**
 * Put a ready reception animal on sale (phase 10). Removes it from receptionAnimals and clears the reception cell.
 * @param {import("./types.js").GameState} state
 * @param {string} receptionCellKey
 * @returns {[boolean, string]} [ok, listingId or reason]
 */
export function addReceptionAnimalToSale(state, receptionCellKey) {
  const now = Math.floor(Date.now() / 1000);
  const receptionAnimals = state.receptionAnimals ?? [];
  const idx = receptionAnimals.findIndex(
    (r) => r.receptionCellKey === receptionCellKey && now >= r.readyAt
  );
  if (idx < 0) {
    const first = receptionAnimals.find((r) => r.receptionCellKey === receptionCellKey);
    return [false, first ? "AnimalNotReady" : "NoAnimalInReception"];
  }
  const rec = receptionAnimals[idx];
  state.receptionAnimals = receptionAnimals.filter((_, i) => i !== idx);
  state.saleListings = state.saleListings ?? [];
  const { duration, price } = getSaleListingDefaults();
  const listingId = `sale_${state.nextTokenId}`;
  state.nextTokenId += 1;
  state.saleListings.push({
    id: listingId,
    zooId: state.myZooId ?? "player",
    animalId: rec.animalId,
    isBaby: false,
    price,
    endAt: now + duration,
    reproductionScoreAtSale: rec.reproductionScoreAtSale ?? getReproductionScore(state),
  });
  state.lastEvolutionAt = now;
  return [true, listingId];
}

/**
 * Remove expired sale listings. If listing was a baby (isBaby), increment deathCountRecent (bébé invendu meurt).
 * If listing was an adult (isBaby false), also increment deathCountRecent (vente échouée = mort adulte).
 * @param {import("./types.js").GameState} state
 * @param {number} nowUnix
 */
export function tickSaleListings(state, nowUnix) {
  const listings = state.saleListings ?? [];
  const kept = [];
  let babyDeaths = 0;
  let adultDeaths = 0;
  for (const listing of listings) {
    if (nowUnix < listing.endAt) {
      kept.push(listing);
    } else if (listing.isBaby) {
      babyDeaths += 1;
    } else {
      adultDeaths += 1;
    }
  }
  state.saleListings = kept;
  const totalDeaths = babyDeaths + adultDeaths;
  if (totalDeaths > 0) state.deathCountRecent = (state.deathCountRecent ?? 0) + totalDeaths;
}

/**
 * Compute sell result for animal at (x,y). Returns [false, reason] or [true, { blockKeys, sellValue }].
 * @param {import("./types.js").GameState} state
 * @param {number} x
 * @param {number} y
 * @returns {[false, string] | [true, { blockKeys: string[], sellValue: number }]}
 */
function getSellAnimalResult(state, x, y) {
  const key = cellKey(x, y);
  const cell = state.grid.cells[key];
  if (cell === null || cell === undefined || cell.kind !== "animal") return [false, "NoAnimal"];
  const animalDef = LootTables.Animals[cell.id];
  if (animalDef === null || animalDef === undefined) throw new Error("TradeService: unknown animal");
  const blockKeys = getBlockKeysFromCell(state, x, y);
  const originKey = blockKeys[0];
  const originCell = state.grid.cells[originKey];
  if (originCell === null || originCell === undefined || originCell.kind !== "animal") return [false, "NoAnimal"];
  const mutationMultiplier = getIncomeMultiplier(originCell.mutation);
  const sellValue = getSellValue(
    animalDef.baseIncomePerSecond,
    originCell.level,
    mutationMultiplier,
    animalDef.sellFactor
  );
  return [true, { blockKeys, sellValue }];
}

/**
 * @param {import("./types.js").GameState} state
 * @param {number} x
 * @param {number} y
 * @returns {[boolean, number | string]}
 */
export function sellAnimalToNpc(state, x, y) {
  const result = getSellAnimalResult(state, x, y);
  if (result[0] === false) return [false, result[1]];
  const { blockKeys, sellValue } = result[1];
  for (const k of blockKeys) delete state.grid.cells[k];
  state.coins += sellValue;
  state.lastEvolutionAt = Math.floor(Date.now() / 1000);
  if (state.stats) state.stats.animalsSold = (state.stats.animalsSold ?? 0) + 1;
  return [true, sellValue];
}
