import fs from "fs";
import { checkIcons, dataRawPath, getJsonData, scriptOutputPath } from "./helpers/file.helper.ts";
import type {
  DataRawDump,
  Item,
  Machine,
  Module,
  Quality,
  RecipeCategory,
  Signal,
} from "./factorio-process-data.models.js";

import { groupPrototypes, type Group } from "./helpers/groups.helper.ts";
import { parseRecipe, type Recipe } from "./helpers/recipes.helper.ts";
import type { ProcessedData } from "./factorio-process-data.models.ts";
import { buildIconTextureMap, walkForIcons } from "./helpers/icons.helper.ts";
import path from "path";

//const modsPath = `${factorioPath}/mods`;

// const tempPath = "./scripts/temp";
// const tempIconsPath = `${tempPath}/icons`;
const isHidden = (o: unknown) => !(o as { hidden?: boolean }).hidden;

/**
 * Extract machines.
 */
function extractMachines(data: DataRawDump): Machine[] {
  return Object.values(data["assembling-machine"])
    .filter(isHidden)
    .map((machine) => ({
      name: machine.name,
      icon: `entity/${machine.name}.png`,
      crafting_categories: machine.crafting_categories,
      crafting_speed: machine.crafting_speed,
      allowed_effects: machine.allowed_effects,
      module_slots: machine.module_slots,
      selection_box: machine.selection_box,
      effect_receiver: machine.effect_receiver,
    }));
}
/**
 * Extract modules.
 */
function extractModules(data: DataRawDump): Module[] {
  return Object.values(data.module)
    .filter(isHidden)
    .map((module) => ({
      name: module.name,
      icon: `item/${module.name}.png`,
      subgroup: module.subgroup,
      category: module.category,
      tier: module.tier,
      order: module.order,
      effect: module.effect,
    }));
}
// TODO : Add quality Modules and quality Machines

/**
 * All the keys that contain item‑like entities.
 */
const ITEM_KEYS = [
  "item",
  "ammo",
  "armor",
  "capsule",
  "gun",
  "item-with-entity-data",
  "module",
  "rail-planner",
  "repair-tool",
  "selection-tool",
  "spidertron-remote",
  "space-platform-starter-pack",
  "tool",
  "fluid",
] as const;
/**
 * Extract all items (and item‑like things) from the raw dump.
 */
function extractItems(dataRaw: DataRawDump): Record<string, Item> {
  return ITEM_KEYS.reduce((acc: Record<string, Item>, key) => {
    const data = dataRaw[key];
    if (data)
      Object.values(data)
        .filter(isHidden)
        .forEach((item) => {
          const isFluid = item.type === "fluid";
          acc[item.name] = {
            name: item.name,
            icon: `${isFluid ? "fluid" : "item"}/${item.name}.png`,
            subgroup: item.subgroup ?? (isFluid ? "fluid" : "other"),
            order: item.order,
          };
        });
    return acc;
  }, {});
}

export async function processData(outputFolder: string) {
  const data = getJsonData(dataRawPath) as DataRawDump;
  const items = extractItems(data);
  const machines = extractMachines(data);
  const modules = extractModules(data);

  const recipeCategories: RecipeCategory[] = Object.values(data["recipe-category"])
    .filter(isHidden)
    .map((c) => ({ name: c.name, subgroup: c.subgroup, order: c.order }));

  const recipes = Object.values(data["recipe"])
    .filter(isHidden)
    .map((o) => parseRecipe(o, items));
  const qualityLevels: Quality[] = Object.values(data.quality)
    .filter(isHidden)
    .map((o) => ({
      ...o,
      icon: `quality/${o.name}.png`,
    }));
  const recipeGroup: Array<Group<Recipe>> = groupPrototypes(recipes, data, false);

  const signals: Array<Signal> = [];
  for (let item of Object.values(items)) {
    signals.push({
      name: item.name,
      subgroup: item.subgroup ?? "",
      icon: item.icon,
      order: item.order,
    });
  }

  const virtualSignals = Object.values(data["virtual-signal"]).filter(isHidden);
  for (let vs of virtualSignals) {
    signals.push({
      name: vs.name,
      subgroup: vs.subgroup ?? "",
      icon: `virtual-signal/${vs.name}.png`,
      order: vs.order,
    });
  }
  for (let quality of qualityLevels) {
    signals.push({
      name: quality.name,
      subgroup: quality.subgroup ?? "",
      icon: quality.icon,
      order: quality.order,
    });
  }
  const signalGroup: Array<Group<Signal>> = groupPrototypes(signals, data, false);

  const output: ProcessedData = {
    qualityLevels,
    machines,
    modules,
    recipeCategories,
    recipeGroup,
    signalGroup,
  };
  fs.mkdirSync(outputFolder, { recursive: true });

  fs.writeFileSync(
    path.resolve(outputFolder, "data.json"),
    JSON.stringify(output, null, 2),
    "utf-8"
  );
  const icons = new Set<string>();
  walkForIcons(output, icons);
  const iconsList = Array.from(icons).sort();
  checkIcons(iconsList);
  await buildIconTextureMap(iconsList, scriptOutputPath, outputFolder);
  console.log(`✅ Done - data written to ${outputFolder}`);
}
