import { DomList } from "./dom-list.js";
import { atlases, makeAtlasImage } from "./atlas.js";
import { Filter } from "./filter.js";
import { createTooltip, tooltipDataToPlain } from "./tooltip.js";
import { emitEvent, listenTo } from "./events.js";
import { getPlannerMultiblockType } from "./planner.js";
import { registerLoadCallback } from "./main.js";
import { lookupFromMetadata, resolveBlockName } from "./ncpf-utils.js";

registerLoadCallback(() => {
  listenTo("config:end", buildBlockPicker);
  listenTo("block-picker:filter:input", buildBlockPicker);
  listenTo("block-picker:selection", () => setBlockPickerRecipe(null));
});

let activeItemRecipe = null;

function buildBlockPicker() {
  const filter = Filter.fromInput("block-picker:filter");

  const grid = new DomList(document.getElementById("block-picker-list"));
  grid.clear();

  atlases.flatMap(a => a.metadata)
      .filter(m => m.configuration === getPlannerMultiblockType() && m.configurationList === "blocks")
      .forEach(m => {
        const item = grid.makeItem();
        item.dataset.index = m.index.toString(10);
        const tooltipData = [...getBlockTooltip(m)];
        item.dataset.tooltip = createTooltip(tooltipData).toString(10);
        if (!filter.test(...tooltipDataToPlain(tooltipData))) {
          item.classList.add("hidden");
        }
        if (tooltipData.some(v => v.type === "meta" && v.casing)) {
          item.dataset.casing = "";
        }
        item.appendChild(makeAtlasImage(m.index));
        item.addEventListener("click", blockPickerClickEvent);
        grid.addItem(item);
      });
}

function blockPickerClickEvent(e) {
  const blockPickerDom = document.getElementById("block-picker-list");
  const items = document.querySelectorAll("#block-picker-list [data-index]");
  if (e.currentTarget.dataset.active !== undefined) {
    items.forEach(i => delete i.dataset.active);
    blockPickerDom.dataset.activeItem = (-1).toString(10);
    delete e.currentTarget.dataset.active;
    emitEvent("block-picker:selection", -1);
    emitEvent("block-picker:selection:clear");
    return;
  }
  items.forEach(i => delete i.dataset.active);
  blockPickerDom.dataset.activeItem = e.currentTarget.dataset.index;
  e.currentTarget.dataset.active = "";
  emitEvent("block-picker:selection", blockPickerDom.dataset.activeItem);
}

function* getBlockTooltip(metadata) {
  const data = lookupFromMetadata(metadata);

  if (!data) {
    console.warn("failed to get data from metadata", metadata);
    return;
  }

  yield data.modules["plannerator:display_name"].display_name;

  let hasAdditionalData = false;

  if ("nuclearcraft:overhaul_sfr:heat_sink" in data.modules) {
    hasAdditionalData = true;
    const heatSink = data.modules["nuclearcraft:overhaul_sfr:heat_sink"];
    yield "Heatsink";
    if (heatSink.cooling) {
      yield `Cooling: ${heatSink.cooling} H/t`;
    }
    if (heatSink.rules) {
      for (const rule of heatSink.rules) {
        yield "Requires " + parseRuleAsTooltip(rule, { configurationHint: metadata.configuration });
      }
    }
  }

  if ("nuclearcraft:overhaul_sfr:casing" in data.modules) {
    hasAdditionalData = true;
    yield "Casing";
    yield {
      type: "meta",
      casing: true,
    };
  }

  if ("nuclearcraft:overhaul_sfr:controller" in data.modules) {
    hasAdditionalData = true;
    yield "Controller";
  }

  if ("nuclearcraft:overhaul_sfr:fuel_cell" in data.modules) {
    hasAdditionalData = true;
    yield "Fuel Cell";
  }

  if ("nuclearcraft:overhaul_sfr:port" in data.modules) {
    hasAdditionalData = true;
    if (data.modules["nuclearcraft:overhaul_sfr:port"].output) {
      yield "Output Port";
    } else {
      yield "Input Port";
    }
  }

  if ("nuclearcraft:overhaul_sfr:irradiator" in data.modules) {
    hasAdditionalData = true;
    yield "Irradiator";
  }

  if ("nuclearcraft:overhaul_sfr:conductor" in data.modules) {
    hasAdditionalData = true;
    yield "Conductor";
  }

  if ("nuclearcraft:overhaul_sfr:neutron_source" in data.modules) {
    hasAdditionalData = true;
    const neutronSource = data.modules["nuclearcraft:overhaul_sfr:neutron_source"];
    yield "Neutron Source";
    yield `Efficiency: ${neutronSource.efficiency}`;
  }

  if ("nuclearcraft:overhaul_sfr:moderator" in data.modules) {
    hasAdditionalData = true;
    const moderator = data.modules["nuclearcraft:overhaul_sfr:moderator"];
    yield "Moderator";
    yield `Flux: ${moderator.flux}`;
    yield `Efficiency: ${moderator.efficiency}`;
  }

  if ("nuclearcraft:overhaul_sfr:reflector" in data.modules) {
    hasAdditionalData = true;
    const reflector = data.modules["nuclearcraft:overhaul_sfr:reflector"];
    yield "Reflector";
    yield `Efficiency: ${reflector.efficiency}`;
    yield `Reflectivity: ${reflector.reflectivity}`;
  }

  if ("nuclearcraft:overhaul_sfr:neutron_shield" in data.modules) {
    hasAdditionalData = true;
    const shield = data.modules["nuclearcraft:overhaul_sfr:neutron_shield"];
    yield "Neutron Shield";
    yield `Efficiency: ${shield.efficiency}`;
    yield `Heat per Flux: ${shield.heat_per_flux}`;
  }

  if (!hasAdditionalData) {
    console.log("unknown block", data);
  }

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

function parseRuleAsTooltip(rule, props) {
  switch (rule.type) {
    case "and":
      return rule.rules.map(r => parseRuleAsTooltip(r, props)).join(" AND ");

    case "or":
      return rule.rules.map(r => parseRuleAsTooltip(r, props)).join(" OR ");

    case "between": {
      const block = resolveBlockName(rule.block, props);
      if (!block) {
        console.warn("could not find block %o", rule.block);
        return "???";
      }
      if (rule.min === rule.max) {
        return `exactly ${rule.min} ${block}`;
      } else if (rule.max === 6) {
        return `at least ${rule.min} ${block}`;
      } else if (rule.min === 0) {
        return `no more than ${rule.max} ${block}`;
      } else {
        return `between ${rule.min} and ${rule.max} ${block}`;
      }
    }

    case "axial": {
      const block = resolveBlockName(rule.block, props);
      if (!block) {
        console.warn("could not find block %o", rule.block);
        return "???";
      }
      if (rule.min === rule.max) {
        return `exactly ${rule.min} axial ${block}`;
      } else if (rule.max === 3) {
        return `at least ${rule.min} axial ${block}`;
      } else if (rule.min === 0) {
        return `no more than ${rule.max} axial ${block}`;
      } else {
        return `between ${rule.min} and ${rule.max} axial ${block}`;
      }
    }

    default:
      console.warn("unknown rule: %o", rule);
      return "???";
  }
}

export function getBlockPickerActiveItem() {
  const blockPickerDom = document.getElementById("block-picker-list");
  return Number(blockPickerDom.dataset.activeItem ?? -1);
}

export function getBlockPickerRecipe() {
  return activeItemRecipe;
}

export function setBlockPickerRecipe(recipe) {
  activeItemRecipe = recipe;
}
