import { world, system } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";

// Toggle this to false if your ActionFormData implementation doesn't accept RawMessage
const USE_RAW = true;
const tr = (key, args = []) =>
  USE_RAW ? (args.length ? { translate: key, with: args } : { translate: key }) : key;
const sizeArgs = (painting) => [String(painting.width), String(painting.height)]; // %1 = width, %2 = height

// Painting metadata with defined center part_id
const paintingData = {
  "bps_paint:painting_1x1": {
    width: 1,
    height: 1,
    center: 1,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "painting_10",
      "template",
    ],
  },
  "bps_paint:painting_2x1": {
    width: 2,
    height: 1,
    center: 1,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "painting_10",
      "template",
    ],
  },
  "bps_paint:painting_2x2": {
    width: 2,
    height: 2,
    center: 3,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "template",
    ],
  },
  "bps_paint:painting_3x2": {
    width: 3,
    height: 2,
    center: 4,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "painting_10",
      "painting_11",
      "painting_12",
      "painting_13",
      "template",
    ],
  },
  "bps_paint:painting_4x2": {
    width: 4,
    height: 2,
    center: 5,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "template",
    ],
  },
  "bps_paint:painting_4x3": {
    width: 4,
    height: 3,
    center: 9,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "painting_10",
      "template",
    ],
  },
  "bps_paint:painting_4x4": {
    width: 4,
    height: 4,
    center: 13,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "template",
    ],
  },
  "bps_paint:painting_2x3": {
    width: 2,
    height: 3,
    center: 5,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "template",
    ],
  },
  "bps_paint:painting_2x4": {
    width: 2,
    height: 4,
    center: 7,
    styles: ["painting_1", "painting_2", "painting_3", "painting_4", "painting_5", "template"],
  },
  "bps_paint:painting_3x3": {
    width: 3,
    height: 3,
    center: 7,
    styles: [
      "painting_1",
      "painting_2",
      "painting_3",
      "painting_4",
      "painting_5",
      "painting_6",
      "painting_7",
      "painting_8",
      "painting_9",
      "painting_10",
      "template",
    ],
  },
};

// ---------- one-time wiring + per-player UI lock ----------

// Only wire once across reloads
if (!globalThis.__BPS_PAINTING_UI_WIRED__) {
  globalThis.__BPS_PAINTING_UI_WIRED__ = true;

  // Track whether a player already has a painting UI open/queued
  globalThis.__BPS_PAINTING_UI_BUSY__ = globalThis.__BPS_PAINTING_UI_BUSY__ ?? new Map();
  const uiBusy = globalThis.__BPS_PAINTING_UI_BUSY__;

  world.beforeEvents.playerInteractWithBlock.subscribe((event) => onPaintingInteract(event, uiBusy));

  // If a player leaves while "busy", clear their lock
  world.afterEvents.playerLeave.subscribe((e) => {
    uiBusy.delete(e.playerId);
  });
}

// ---------------------------------------------------------

function onPaintingInteract(event, uiBusy) {
  const block = event.block;
  const player = event.player;

  const painting = paintingData[block.typeId];
  if (!painting) return;

  // Stable per-player identifier (id on recent APIs; nameTag/name fallback for older)
  const pid = player.id ?? player.nameTag ?? player.name ?? `player:${Math.random()}`;

  // If a form is already open/queued for this player, ignore this interaction
  if (uiBusy.get(pid)) {
    event.cancel = true;
    return;
  }

  event.cancel = true;

  const direction = block.permutation.getState("minecraft:cardinal_direction");

  const center = getCenterFromPart(block, painting);
  if (!center) {
    player.sendMessage(tr("ui.bps_paint.center_not_found", sizeArgs(painting)));
    return;
  }

  // Mark as busy BEFORE scheduling the show() to avoid racey double-queues
  uiBusy.set(pid, true);
  openPaintingStyleMenu(player, center, painting, pid, uiBusy);
}

function openPaintingStyleMenu(player, centerBlock, painting, pid, uiBusy) {
  const form = new ActionFormData()
    .title(tr("ui.bps_paint.title", sizeArgs(painting)))
    .body(tr("ui.bps_paint.body", sizeArgs(painting)));

  painting.styles.forEach((style) =>
    form.button(
      tr(`style.bps_paint.${painting.width}x${painting.height}_${style}`),
      `textures/bps/paint/blocks/${painting.width}_${painting.height}/${style}.png`
    )
  );

  // Keep show() off the beforeEvent tick; the lock is already set.
  system.run(() => {
    Promise.resolve()
      .then(() => form.show(player))
      .then((response) => {
        if (response.canceled) {
          player.sendMessage(tr("ui.bps_paint.canceled", sizeArgs(painting)));
          return;
        }

        const style = painting.styles[response.selection];
        if (!style) {
          player.sendMessage(tr("ui.bps_paint.invalid_selection", sizeArgs(painting)));
          return;
        }

        changePaintingStyle(centerBlock, painting, style, player);
      })
      .catch((e) => {
      })
      .finally(() => {
        uiBusy.delete(pid); // always release the lock
      });
  });
}

function getCenterFromPart(clickedBlock, painting) {
  const { width, height, center } = painting;
  const dim = clickedBlock.dimension;
  const loc = clickedBlock.location;
  const permutation = clickedBlock.permutation;
  const direction = permutation.getState("minecraft:cardinal_direction");
  const partId = permutation.getState("bps_paint:part_id");


  const index = partId - 1;
  const row = Math.floor(index / width);
  const col = index % width;

  const centerIndex = center - 1;
  const centerRow = Math.floor(centerIndex / width);
  const centerCol = centerIndex % width;

  const dx = col - centerCol;
  const dz = col - centerCol; // lateral offset reused for z when facing east/west
  const dy = row - centerRow;

  let x = loc.x;
  let y = loc.y + dy;
  let z = loc.z;

  switch (direction) {
    case "north":
      x -= dx;
      break;
    case "south":
      x += dx;
      break;
    case "east":
      z -= dz;
      break;
    case "west":
      z += dz;
      break;
    default:
      return null;
  }

  const centerBlock = dim.getBlock({ x, y, z });
  if (!centerBlock || centerBlock.typeId !== clickedBlock.typeId) {
    return null;
  }

  const actualPartId = centerBlock.permutation.getState("bps_paint:part_id");
  if (actualPartId !== center) {
    return null;
  }

  return centerBlock;
}

function changePaintingStyle(centerBlock, painting, newStyle, player) {
  const dim = centerBlock.dimension;
  const base = centerBlock.location;
  const direction = centerBlock.permutation.getState("minecraft:cardinal_direction");

  const { width, height, center } = painting;

  let part = 1;
  for (let row = 0; row < height; row++) {
    for (let col = 0; col < width; col++) {
      if (part === center) {
        part++;
        continue;
      }

      let x = base.x;
      let y = base.y + (height - 1 - row);
      let z = base.z;

      switch (direction) {
        case "south":
          x -= col;
          break;
        case "north":
          x += col;
          break;
        case "east":
          z += col;
          break;
        case "west":
          z -= col;
          break;
      }

      const block = dim.getBlock({ x, y, z });
      if (!block || block.typeId !== centerBlock.typeId) {
        part++;
        continue;
      }

      try {
        block.setPermutation(
          block.permutation
            .withState("bps_paint:part_id", part)
            .withState("minecraft:cardinal_direction", direction)
            .withState("bps_paint:painting_name", newStyle)
        );
      } catch (e) {
      }

      part++;
    }
  }

  // Update center block
  try {
    centerBlock.setPermutation(
      centerBlock.permutation
        .withState("bps_paint:part_id", center)
        .withState("minecraft:cardinal_direction", direction)
        .withState("bps_paint:painting_name", newStyle)
    );
  } catch (e) {
    player.sendMessage(tr("ui.bps_paint.center_update_failed", sizeArgs(painting)));
  }
}
