import { getAsciiArt } from "../util/asciiArt.ts";
import { toCase } from "util/caseManagement.ts";
import { ArgParser } from "./argParser.ts";
import { colorize } from "./style.ts";
import { selectMenuInteractive } from "./selectMenu.ts";
import { TerminalBlock, TerminalLayout } from "./TerminalLayout.ts";
import { cliAlert, cliLog } from "./prompts.ts";
import type { ITool } from "../types.ts";
import { InputManager } from "./InputManager.ts";

// Register tools here (filename, no extension)
const toolRegistry: [string, Promise<{ default: ITool }>][] = [
  ["checkCode", import("../tools/checkCode.ts")],
  ["fieldRename", import("../tools/fieldRename.ts")],
  ["listFormFields", import("../tools/listFormFields.ts")],
  ["deleteFields", import("../tools/deleteFields.ts")],
  ["fieldVisibility", import("../tools/fieldVisibility.ts")],
];

export class PdfToolsCli {
  private tools: Map<string, ITool> = new Map();
  private terminalLayout = new TerminalLayout();
  closeMessage?: string;

  private args = ArgParser.parse(Deno.args).setFlagDefs({
    help: ["-h", "--help"],
    banana: ["-b", "--banana"],
  });

  async importTools() {
    for (const [name, toolfile] of toolRegistry) {
      const t = await toolfile;
      try {
        if (t.default) {
          this.tools.set(
            toCase(name, "title"),
            t.default,
          );
        }
      } catch (e) {
        cliLog(e + "\n", this.terminalLayout.getBlock("body"));
      }
    }
  }

  private async banana() {
    const asciiArt = await getAsciiArt("banana");
    this.closeMessage = colorize(asciiArt, "yellow");
  }

  private async help() {
    this.terminalLayout.clear();
    this.ensmallenHeader("Help");
    const bodyBlock = this.terminalLayout.getBlock("body");
    bodyBlock.clearAll();
    await cliAlert("BearMetal PDF CLI\n", bodyBlock);
    await this.embiggenHeader();
  }

  public async run() {
    const im = InputManager.getInstance();
    im.activate();
    im.addEventListener("exit", () => {
      this.closeMessage = "Exiting...";
      this.cleanup();
    });
    try {
      await this.importTools();
      const titleBlock = new TerminalBlock();
      this.terminalLayout.register("title", titleBlock);
      const bodyBlock = new TerminalBlock();
      this.terminalLayout.register("body", bodyBlock);
      if (this.args.getFlag("banana")) {
        titleBlock.setFixedHeight(0);
        await this.banana();
        return;
      }
      if (this.args.getFlag("help") && !this.args.task) {
        await this.help();
        return;
      } else if (this.args.nonFlags.length === 0 || !this.args.task) {
        this.embiggenHeader();
        await this.toolMenu();
      } else {
        const task = this.args.task;
        await this.runTool(toCase(task, "title"));
      }
    } finally {
      this.cleanup();
      Deno.exit(0);
    }
  }

  private cleanup() {
    this.terminalLayout.clearAll();
    InputManager.getInstance().deactivate();
    Deno.stdin.setRaw(false);
    if (this.closeMessage) console.log(this.closeMessage);
  }

  private async toolMenu() {
    const tools = this.tools.keys().toArray();
    const bodyBlock = this.terminalLayout.getBlock("body");
    bodyBlock.clearAll();
    bodyBlock.setPreserveHistory(false);
    const selected = await selectMenuInteractive(
      "Choose a tool",
      tools.concat(["Help", "Exit"]),
      {
        terminalBlock: bodyBlock,
      },
    );
    if (!selected) return;
    if (selected === "Exit") {
      return;
    }
    await this.runTool(selected);
    await this.toolMenu();
  }

  private async runTool(toolName: string) {
    if (toolName === "Help") {
      return await this.help();
    }
    const tool = this.tools.get(toolName);
    if (tool) {
      this.ensmallenHeader(tool.name + " - " + tool.description);
      const bodyBlock = this.terminalLayout.getBlock("body");
      bodyBlock.clearAll();
      tool.setBlock?.(bodyBlock);
      if (this.args.getFlag("help")) {
        await tool.help?.();
      } else {
        await tool.run(...this.args.taskArgs);
        await tool.done?.();
      }
      await this.embiggenHeader();
    } else {
      this.closeMessage = "No tool found for " + toolName;
    }
  }

  private ensmallenHeader(subtitle: string) {
    this.terminalLayout.clear();
    const titleBlock = this.terminalLayout.getBlock("title");
    titleBlock.clear();
    titleBlock.setFixedHeight(3);
    titleBlock.setLines([
      colorize("BearMetal PDF Tools", "porple"),
      colorize(subtitle, "gray"),
      "-=".repeat(Deno.consoleSize().columns / 2),
    ]);
  }

  private async embiggenHeader() {
    const titleBlock = this.terminalLayout.getBlock("title");
    titleBlock.clear();
    const lines: string[] = [];
    for (const t of ["bearmetal:porple", "pdftools:cyan"]) {
      const [name, color] = t.split(":");
      const asciiArt = await getAsciiArt(name);
      lines.push(...colorize(asciiArt, color).split("\n"));
    }
    titleBlock.setFixedHeight(lines.length);
    titleBlock.setLines(lines);
  }
}
