import { registerLoadCallback } from "./main.js";
import { awaitEvent, listenTo } from "./events.js";
import {
  createPlannerCell,
  createPlannerPlane,
  getPlannerDom,
  getPlannerMultiblockSize, getPlannerMultiblockType,
  maxMultiblockSize
} from "./planner.js";
import { DomList } from "./dom-list.js";

registerLoadCallback(() => {
  listenTo("planner:resize", e => {
    if (e.detail.state) {
      initializeResize();
    } else {
      cleanUpResize();
    }
  });

  awaitEvent("dev-mode:end").then(async () => {
    await awaitEvent("fileLoad:end");
    initializeResize();
  });
});

function createButton({ axis, n, add, topLeft }) {
  const div = document.createElement("div");
  div.innerText = add ? "+" : "-";
  if (axis === "y") {
    div.classList.add(`planner--resize--${add ? "add" : "remove"}-layer`);
    if (!add) {
      div.addEventListener("mouseenter", () => highlight(axis, n, add));
      div.addEventListener("mouseleave", () => highlight(null));
    }
  } else {
    div.classList.add(`planner--resize--${add ? "add" : "remove"}-${axis}`);
    div.classList.add(`planner--resize--${topLeft ? "top-left" : "bottom-right"}`);
    div.style.setProperty(`--${axis}`, `${n}`);
    div.addEventListener("mouseenter", () => highlight(axis, n, add));
    div.addEventListener("mouseleave", () => highlight(null));
  }
  div.addEventListener("click", e => resize(axis, n, add, e));
  return div;
}

function highlight(axis, n, add) {
  const planner = getPlannerDom();
  const resizes = [...planner.querySelectorAll(":scope > .planner--resize")];
  if (!axis) {
    resizes.forEach(r => {
      r.querySelectorAll(":scope > .planner--resize--highlight").forEach(e => r.removeChild(e));
    });
    return;
  }
  if (axis === "y") {
    const div = document.createElement("div");
    div.classList.add("planner--resize--highlight", `planner--resize--highlight__remove-layer`);
    resizes[n].appendChild(div);
    return;
  }
  resizes.forEach(r => {
    const div = document.createElement("div");
    div.classList.add("planner--resize--highlight", `planner--resize--highlight__${add ? "add" : "remove"}-${axis}`);
    div.style.setProperty(`--${axis}`, `${n}`);
    r.appendChild(div);
  });
}

function resize(axis, n, add, e) {
  const planner = getPlannerDom();
  const size = getPlannerMultiblockSize();
  if (!add) {
    if (axis === "y") {
      const resizes = planner.querySelectorAll(`:scope > .planner--resize`);
      planner.removeChild(resizes[n]);
      size[1]--;
    } else {
      const tiles = planner.querySelectorAll(`[data-${axis}="${n}"]`);
      const tileGroups = Object.values(Object.groupBy(tiles, t => t.parentElement.dataset.y));
      for (const tg of tileGroups) {
        const parent = tg[0].parentElement;
        tg.forEach(t => parent.removeChild(t));
      }
      size[axis === "x" ? 0 : 2]--;
    }
  } else {
    if (axis === "y") {
      const list = new DomList(planner);
      const plane = list.makeItem();
      createPlannerPlane(plane, 0, null);
      const parentPlane = document.createElement("div");
      parentPlane.classList.add("planner--resize");
      parentPlane.appendChild(plane)
      const nextSibling = planner.querySelector(`:scope > .planner--resize[data-y="${n+1}"]`);
      planner.insertBefore(parentPlane, nextSibling);
      size[1]++;
    } else {
      const tiles = planner.querySelectorAll(`[data-${axis}="${n}"]`);
      const tileGroups = Object.values(Object.groupBy(tiles, t => t.parentElement.dataset.y));
      for (const tg of tileGroups) {
        const parent = tg[0].parentElement;
        const grid = new DomList(parent);
        tg.forEach(t => {
          const cell = grid.makeItem();
          createPlannerCell(cell, 0, 0, 0, -1);
          parent.insertBefore(cell, axis === "x" ? t : tg[0]);
        });
      }
      size[axis === "x" ? 0 : 2]++;
    }
  }
  fixPlannerNumbering();
  cleanUpResize();
  initializeResize();
}

function initializeResize() {
  const planner = getPlannerDom();
  const size = getPlannerMultiblockSize();
  const type = getPlannerMultiblockType();
  const grids = [...planner.querySelectorAll(":scope > .grid")];
  grids.forEach((grid, gridIndex) => {
    const casing = gridIndex === 0 || gridIndex === grids.length - 1;

    const removedGrid = planner.removeChild(grid);
    const newDiv = document.createElement("div");
    newDiv.classList.add("planner--resize");
    newDiv.style.setProperty("--width", `${size[0]}`);
    newDiv.style.setProperty("--height", `${size[2]}`);
    newDiv.dataset.y = gridIndex.toString(10);
    if (casing) {
      newDiv.dataset.casing = "";
    }

    if (!casing && size[1] > maxMultiblockSize[type][1]) {
      newDiv.appendChild(createButton({ axis: "y", add: false, n: gridIndex }));
    }
    if (!casing) {
      for (let x = 0; x < size[0] - 1 && size[0] < maxMultiblockSize[type][0]; x++) {
        newDiv.appendChild(createButton({ axis: "x", add: true, n: x+1, topLeft: true }));
      }
      for (let x = 0; x < size[0] - 2 && size[0] > maxMultiblockSize[type][0]; x++) {
        newDiv.appendChild(createButton({ axis: "x", add: false, n: x+1, topLeft: true }));
      }
      for (let z = 0; z < size[2] - 1 && size[2] < maxMultiblockSize[type][2]; z++) {
        newDiv.appendChild(createButton({ axis: "z", add: true, n: z+1, topLeft: true }));
      }
      for (let z = 0; z < size[2] - 2 && size[2] > maxMultiblockSize[type][2]; z++) {
        newDiv.appendChild(createButton({ axis: "z", add: false, n: z+1, topLeft: true }));
      }
    }

    newDiv.appendChild(removedGrid);
    planner.appendChild(newDiv);

    if (!casing) {
      for (let x = 0; x < size[0] - 1 && size[0] < maxMultiblockSize[type][0]; x++) {
        newDiv.appendChild(createButton({ axis: "x", add: true, n: x+1, topLeft: false }));
      }
      for (let x = 0; x < size[0] - 2 && size[0] > maxMultiblockSize[type][0]; x++) {
        newDiv.appendChild(createButton({ axis: "x", add: false, n: x+1, topLeft: false }));
      }
      for (let z = 0; z < size[2] - 1 && size[2] < maxMultiblockSize[type][2]; z++) {
        newDiv.appendChild(createButton({ axis: "z", add: true, n: z+1, topLeft: false }));
      }
      for (let z = 0; z < size[2] - 2 && size[2] > maxMultiblockSize[type][2]; z++) {
        newDiv.appendChild(createButton({ axis: "z", add: false, n: z+1, topLeft: false }));
      }
    }

    planner.appendChild(newDiv);

    if (gridIndex !== grids.length - 1 && size[1] < maxMultiblockSize[type][1]) {
      planner.appendChild(createButton({ axis: "y", add: true, n: gridIndex }));
    }
  });
}

function cleanUpResize() {
  const planner = getPlannerDom();
  planner.replaceChildren(...planner.querySelectorAll(":scope > .planner--resize > .grid"), ...planner.querySelectorAll(":scope > template"));
}

function fixPlannerNumbering() {
  const planner = getPlannerDom();
  const size = getPlannerMultiblockSize();
  const grids = planner.querySelectorAll(":scope > .planner--resize > .grid");
  grids.forEach(grid => {
    grid.style.setProperty("--width", size[0].toString(10));
    const tiles = [...grid.querySelectorAll("[data-tile]")];
    for (let z = 0; z < size[2]; z++) {
      for (let x = 0; x < size[0]; x++) {
        const tile = tiles.shift();
        tile.dataset.x = x.toString(10);
        tile.dataset.z = z.toString(10);
      }
    }
  });
}
