import { registerLoadCallback } from "./main.js";
import { listenTo } from "./events.js";
import { configuration } from "./configuration.js";
import { getPlannerDom, getPlannerMultiblockType, getSelectedCells } from "./planner.js";
import { DomList } from "./dom-list.js";
import { getAtlasIndexFromMetadata, getAtlasMetadata, makeAtlasImage } from "./atlas.js";
import { deleteSolverMetadata, getSolverMetadata, setSolverMetadata } from "./solver.js";
import {
  checkEquivalence,
  findFullEntry,
  findFullEntryAnywhere,
  findFullEntryFromAtlasMetadata,
  lookupFromMetadata, stripEntryToMinimums
} from "./ncpf-utils.js";
import { createTooltip, setTooltip, tooltipDataToPlain } from "./tooltip.js";
import { Filter } from "./filter.js";
import { debounce } from "./dom-utils.js";
import { getBlockPickerActiveItem, setBlockPickerRecipe } from "./block-picker.js";

const defaultRecipes = {
  ["nuclearcraft:overhaul_sfr"]: {
    coolant_recipe: {
      elements: [
        { name: "water", type: "legacy_fluid" },
        { name: "condensate_water", type: "legacy_fluid" },
      ],
      type: "list",
    },
  },
};

registerLoadCallback(() => {
  listenTo([
    "config:end",
    "solver:reset:done",
  ], rescanDesignRecipes);

  listenTo([
    "planner:selection:removed",
    "planner:selection:added",
    "block-picker:selection",
  ], rescanSelectionRecipes);
});

function initializeRecipePicker({
                                  parent,
                                  title,
                                  entryListType,
                                  multiblockType,
                                  recipes,
                                  currentSelection,
                                  updateSelection,
}) {

  parent.querySelectorAll('[data-text="recipe:type"]')
      .forEach(e => e.innerText = title);

  function updateSelectedRecipe(selectedRecipe) {
    if (!selectedRecipe) {
      parent.querySelectorAll('[data-text="recipe:selected"]')
          .forEach(e => e.innerText = "Unknown");
      parent.querySelectorAll('[data-atlas="recipe:selected"]')
          .forEach(e => e.replaceChildren(makeAtlasImage(-1)));
      return;
    }
    const selectedRecipeName = selectedRecipe.modules["plannerator:display_name"].display_name;
    const selectedAtlasId = getAtlasIndexFromMetadata(selectedRecipe, multiblockType, entryListType);
    const metadata = getAtlasMetadata(selectedAtlasId);
    parent.querySelectorAll('[data-text="recipe:selected"]')
        .forEach(e => e.innerText = selectedRecipeName);
    parent.querySelectorAll('[data-atlas="recipe:selected"]')
        .forEach(e => e.replaceChildren(makeAtlasImage(selectedAtlasId)));
    parent.querySelectorAll('.recipe--selected')
        .forEach(e => setTooltip(e, [...getRecipeTooltip(selectedRecipe, metadata)]));
  }
  updateSelectedRecipe(currentSelection);

  function handleDismiss() {
    console.log("dismiss");
    parent.classList.remove("selecting");
    window.removeEventListener("click", handleDismiss);
  }
  parent.addEventListener("click", e => e.stopPropagation());

  const filterElem = parent.querySelector('[data-input="recipe:filter"]');

  function updateRecipeList() {
    const filter = Filter.fromInput(filterElem);
    const recipeList = new DomList(parent.querySelector(":scope > .select"));
    recipeList.clear();
    console.log(recipes);
    for (let i = 0; i < recipes.length; i++) {
      const recipe = recipes[i];
      const recipeItem = recipeList.makeItem();

      const recipeName = recipe.modules["plannerator:display_name"].display_name;
      const atlasId = getAtlasIndexFromMetadata(recipe, multiblockType, entryListType);
      const metadata = getAtlasMetadata(atlasId);

      recipeItem.querySelectorAll('[data-text="recipe:item"]')
          .forEach(e => e.innerText = recipeName);
      recipeItem.querySelectorAll('[data-atlas="recipe:item"]')
          .forEach(e => e.replaceChildren(makeAtlasImage(atlasId)));

      recipeItem.addEventListener("click", () => {
        handleDismiss();
        updateSelectedRecipe(recipe);
        updateSelection(recipe);
      });

      const tooltipData = [...getRecipeTooltip(recipe, metadata)];
      setTooltip(recipeItem, tooltipData);
      if (!filter.test(recipeName, ...tooltipDataToPlain(tooltipData))) {
        recipeItem.classList.add("hidden");
      }

      recipeList.addItem(recipeItem);
    }
  }

  updateRecipeList();
  filterElem.addEventListener("input", debounce(updateRecipeList));

  parent.querySelectorAll(':scope > .recipe--selected').forEach(e => {
    e.addEventListener("click", () => {
      parent.classList.add("selecting");
      parent.querySelector('[autofocus]').focus();
      window.addEventListener("click", handleDismiss);
    });
  });
}

function rescanDesignRecipes() {
  console.log("rescan recipes");
  console.log(configuration);

  const multiblockType = getPlannerMultiblockType();

  const configs = [
    ...Object.entries(configuration.configuration),
    ...configuration.addons.flatMap(a => Object.entries(a.configuration)),
  ].filter(([type]) => type === multiblockType);

  const designRecipes = new DomList(
      document.getElementById("recipe-selector:design"),
      document.getElementById("recipe-selector:template"),
  );
  designRecipes.clear();

  if (multiblockType === "nuclearcraft:overhaul_sfr") {
    const coolantRecipes = configs.filter(([, v]) => "coolant_recipes" in v && v.coolant_recipes.length > 0)
        .flatMap(([, v]) => v.coolant_recipes);

    const designItem = designRecipes.makeItem();

    const plannerDom = getPlannerDom();
    const plannerMetadata = getSolverMetadata(plannerDom);
    let currentSelection = plannerMetadata?.coolant_recipe;
    if (!plannerMetadata) {
      currentSelection = defaultRecipes[multiblockType].coolant_recipe;
      setSolverMetadata(plannerDom, {
        coolant_recipe: currentSelection,
      });
    }
    currentSelection = findFullEntry("coolant_recipes", currentSelection, { configurationHint: multiblockType });

    initializeRecipePicker({
      parent: designItem,
      title: "Coolant Recipe",
      entryListType: "coolant_recipes",
      recipes: coolantRecipes,
      updateSelection: r => setSolverMetadata(plannerDom, { coolant_recipe: r }),
      multiblockType,
      currentSelection,
    });

    designRecipes.addItem(designItem);
  }
}

function rescanSelectionRecipes() {
  const selectedCells = getSelectedCells();
  const selectedTiles = new Set(selectedCells.map(v => Number(v.dataset.tile)));
  const pickerTile = getBlockPickerActiveItem();

  const designRecipes = new DomList(
      document.getElementById("recipe-selector:selection"),
      document.getElementById("recipe-selector:template"),
  );
  designRecipes.clear();

  if ((selectedTiles.size !== 1 || selectedTiles.has(-1)) && pickerTile === -1) {
    return;
  }

  const multiblockType = getPlannerMultiblockType();

  const tileMetadata = getAtlasMetadata(selectedCells.length > 0 ? selectedCells[0].dataset.tile : pickerTile);
  const tiles = findFullEntryFromAtlasMetadata(tileMetadata, { all: true });

  console.log(tiles);

  if (!tiles[0] || !tiles[0].modules || !tiles[0].modules["ncpf:block_recipes"]) {
    return;
  }

  const cellRecipes = selectedCells.map(v => getSolverMetadata(v)?.block_recipe);
  const recipeSet = cellRecipes.some(v => v);
  const recipeAllSame = cellRecipes.every(v => v === cellRecipes[0] || checkEquivalence(v, cellRecipes[0]));
  console.log(">", cellRecipes, recipeSet, recipeAllSame);

  const recipes = tiles.flatMap(t => t.modules["ncpf:block_recipes"].recipes);

  recipes.unshift({
    modules: {
      ["plannerator:display_name"]: {
        display_name: "Unfiltered",
      },
    },
  });

  let currentRecipe = null
  if (recipeAllSame) {
    if (recipeSet) {
      currentRecipe = recipes.find(r => checkEquivalence(cellRecipes[0], r));
    } else {
      currentRecipe = recipes[0];
    }
  }

  const designItem = designRecipes.makeItem();

  initializeRecipePicker({
    parent: designItem,
    title: "Block Recipe",
    entryType: "ncpf:block_recipes",
    recipes,
    multiblockType,
    updateSelection: (e) => {
      if (e === recipes[0]) {
        selectedCells.forEach(v => deleteSolverMetadata(v));
        return;
      }
      const stripped = stripEntryToMinimums(e);
      selectedCells.forEach(v => setSolverMetadata(v, { block_recipe: stripped }));
      if (pickerTile !== -1) {
        setBlockPickerRecipe(e);
      }
    },
    currentSelection: currentRecipe,
  });

  designRecipes.addItem(designItem);
}

function* getRecipeTooltip(recipe, metadata) {
  const multiblockType = getPlannerMultiblockType();
  let hasAdditionalData = false;

  if ("nuclearcraft:overhaul_sfr:coolant_recipe_stats" in recipe.modules) {
    hasAdditionalData = true;
    const stats = recipe.modules["nuclearcraft:overhaul_sfr:coolant_recipe_stats"];

    const { entry: output, type } = findFullEntryAnywhere(stats.output, { configurationHint: multiblockType });
    const outputName = output.modules["plannerator:display_name"].display_name;
    const atlasId = getAtlasIndexFromMetadata(output, multiblockType, type);

    yield `Heat: ${stats.heat}`;
    yield `Output:`
    yield `Ratio ${stats.output_ratio}`;
    yield {
      type: "item",
      atlasIndex: atlasId,
      name: outputName,
    };
  }

  if ("nuclearcraft:overhaul_sfr:fuel_stats" in recipe.modules) {
    hasAdditionalData = true;
    const stats = recipe.modules["nuclearcraft:overhaul_sfr:fuel_stats"];

    const { entry: output, type } = findFullEntryAnywhere(stats.output, { configurationHint: multiblockType });
    const outputName = output.modules["plannerator:display_name"].display_name;
    const atlasId = getAtlasIndexFromMetadata(output, multiblockType, type);

    yield `Efficiency: ${stats.efficiency}`;
    yield `Heat: ${stats.heat}`;
    yield `Time: ${stats.time}`;
    yield `Criticality: ${stats.criticality}`;
    if (stats.self_priming) {
      yield "Self-priming";
    }
    yield {
      type: "item",
      atlasIndex: atlasId,
      name: outputName,
      prefix: "Output: ",
    };
  }

  if ("nuclearcraft:overhaul_sfr:irradiator_stats" in recipe.modules) {
    hasAdditionalData = true;
    const stats = recipe.modules["nuclearcraft:overhaul_sfr:irradiator_stats"];

    const { entry: output, type } = findFullEntryAnywhere(stats.output, { configurationHint: multiblockType });
    const outputName = output.modules["plannerator:display_name"].display_name;
    const atlasId = getAtlasIndexFromMetadata(output, multiblockType, type);

    yield `Efficiency: ${stats.efficiency}`;
    yield `Heat: ${stats.heat}`;
    yield {
      type: "item",
      atlasIndex: atlasId,
      name: outputName,
      prefix: "Output: ",
    };
  }

  if (!hasAdditionalData) {
    console.log("unknown recipe", recipe, metadata);
  }

  if (!metadata) {
    console.trace("no metadata for recipe", recipe, metadata);
    return;
  }

  if (metadata.configurationAddon) {
    yield {
      type: "italics",
      text: metadata.configurationAddon.name,
    };
  }
}
