import color from "picocolors";
import { initKeypress, onKey, stopKeypress } from "./keyboard.js";
import { clearScreen, padEnd, strWidth, centerPad } from "./utils/terminal.js";

export async function gridSelect(options) {
  const {
    items,
    cols = 3,
    colWidth = 24,
    title = "",
    renderHeader = null,
    updateInfo = null,
    headerGap = 2,
    menuGap = 2,
    rowGap = 1,
    instructions = "←→ 选择 | Enter 确认 | Esc 退出",
    onCancel = "exit", // "exit" | "back"
    mapper,
    showUpdateButton = true,
  } = options;

  const hasUpdate = showUpdateButton && !!updateInfo;
  const mapResult = mapper || ((item, isUpdate) => (isUpdate ? { isUpdate: true } : item));

  let current = 0;
  let onUpdate = hasUpdate;
  let resolved = false;
  const rows = Math.ceil((items?.length || 0) / cols);
  const termWidth = process.stdout.columns || 80;
  const totalWidth = cols * colWidth;
  const pad = " ".repeat(Math.max(0, Math.floor((termWidth - totalWidth) / 2)));

  function render() {
    clearScreen();

    if (renderHeader) {
      console.log(renderHeader(onUpdate));
    }

    for (let i = 0; i < headerGap; i++) console.log("");

    if (title) {
      const titlePad = centerPad(title, termWidth - 4);
      console.log(titlePad + color.bgMagenta(color.white(` ${title} `)));
    }

    if (instructions) {
      console.log("\n" + pad + color.dim(instructions));
    } else {
      console.log("");
    }

    for (let i = 0; i < menuGap; i++) console.log("");

    if (!items || items.length === 0) {
      console.log(color.yellow("暂无可选项"));
      return;
    }

    for (let row = 0; row < rows; row++) {
      let line = "";
      let descLine = "";

      for (let col = 0; col < cols; col++) {
        const idx = row * cols + col;
        if (idx < items.length) {
          const item = items[idx];
          if (!onUpdate && idx === current) {
            line += color.cyan("[" + item.name + "]");
          } else {
            line += " " + item.name + " ";
          }
          line += " ".repeat(Math.max(0, colWidth - strWidth(item.name) - 2));
          descLine += padEnd(item.desc || "", colWidth);
        }
      }

      console.log(pad + line);
      console.log(pad + color.dim(descLine));
      for (let i = 0; i < rowGap; i++) console.log("");
    }
  }

  return new Promise(resolve => {
    initKeypress();
    render();

    onKey((str, key) => {
      if (!key || resolved) return;

      const row = Math.floor(current / cols);
      const col = current % cols;

      switch (key.name) {
        case "up":
          if (!onUpdate && row === 0 && hasUpdate) {
            onUpdate = true;
            render();
          } else if (!onUpdate && row > 0) {
            current -= cols;
            render();
          }
          break;
        case "down":
          if (onUpdate) {
            onUpdate = false;
            render();
          } else if (row < rows - 1 && current + cols < items.length) {
            current += cols;
            render();
          }
          break;
        case "left":
          if (!onUpdate && col > 0) {
            current--;
            render();
          }
          break;
        case "right":
          if (!onUpdate && col < cols - 1 && current < items.length - 1) {
            current++;
            render();
          }
          break;
        case "return":
          resolved = true;
          stopKeypress();
          setImmediate(() => {
            const isUpdateSelection = onUpdate && hasUpdate;
            const payload = isUpdateSelection ? null : items[current];
            resolve(mapResult(payload, isUpdateSelection));
          });
          break;
        case "escape":
          resolved = true;
          stopKeypress();
          clearScreen();
          if (onCancel === "back") {
            setImmediate(() => resolve("back"));
          } else {
            console.log(color.yellow("再见!"));
            process.exit(0);
          }
          break;
        case "c":
          if (key.ctrl) {
            resolved = true;
            stopKeypress();
            clearScreen();
            if (onCancel === "back") {
              setImmediate(() => resolve("back"));
            } else {
              console.log(color.yellow("再见!"));
              process.exit(0);
            }
          }
          break;
      }
    });
  });
}
