import { readFileSync } from "node:fs";
import { rootPath } from "./config";

export type WindowsFsReadOnlyOperation = "pwd" | "ls" | "cat" | "head" | "tail" | "stat" | "wc" | "rg";

export const windowsFsReadOnlyOperations = new Set<string>(["pwd", "ls", "cat", "head", "tail", "stat", "wc", "rg"]);

interface WindowsRgPolicy {
  timeoutMs: number;
  maxFiles: number;
  maxMatches: number;
  maxBytesPerFile: number;
}

const configPath = "config/unidesk-cli.yaml";
const commonScriptSource = loadScript("common.ps1");
const operationScriptSources: Record<WindowsFsReadOnlyOperation, string> = {
  pwd: loadScript("pwd.ps1"),
  ls: loadScript("ls.ps1"),
  cat: loadScript("cat.ps1"),
  head: loadScript("head-tail.ps1"),
  tail: loadScript("head-tail.ps1"),
  stat: loadScript("stat.ps1"),
  wc: loadScript("wc.ps1"),
  rg: loadScript("rg.ps1"),
};

export function isWindowsFsReadOnlyOperation(operation: string): operation is WindowsFsReadOnlyOperation {
  return windowsFsReadOnlyOperations.has(operation);
}

export function windowsFsReadOnlyScript(basePath: string | null, operation: WindowsFsReadOnlyOperation, args: string[]): string {
  const rgPolicy = readWindowsRgPolicy();
  const variables = [
    `$basePath = ${powerShellSingleQuote(basePath ?? "")}`,
    `$operation = ${powerShellSingleQuote(operation)}`,
    `$argsJsonB64 = ${powerShellSingleQuote(Buffer.from(JSON.stringify(args), "utf8").toString("base64"))}`,
    `$rgPolicyJsonB64 = ${powerShellSingleQuote(Buffer.from(JSON.stringify(rgPolicy), "utf8").toString("base64"))}`,
  ].join("; ");
  return `${variables}; ${commonScriptSource} ${operationScriptSources[operation]}`;
}

function loadScript(name: string): string {
  return readFileSync(new URL(`./ssh-windows-fs/${name}`, import.meta.url), "utf8");
}

function readWindowsRgPolicy(): WindowsRgPolicy {
  const document = asRecord(Bun.YAML.parse(readFileSync(rootPath(configPath), "utf8")), configPath);
  const trans = requiredRecord(document, "trans", configPath);
  const windowsFs = requiredRecord(trans, "windowsFs", `${configPath}#trans`);
  const rg = requiredRecord(windowsFs, "rg", `${configPath}#trans.windowsFs`);
  return {
    timeoutMs: positiveInt(rg, "timeoutMs", `${configPath}#trans.windowsFs.rg`),
    maxFiles: positiveInt(rg, "maxFiles", `${configPath}#trans.windowsFs.rg`),
    maxMatches: positiveInt(rg, "maxMatches", `${configPath}#trans.windowsFs.rg`),
    maxBytesPerFile: positiveInt(rg, "maxBytesPerFile", `${configPath}#trans.windowsFs.rg`),
  };
}

function asRecord(value: unknown, path: string): Record<string, unknown> {
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error(`${path} must be an object`);
  return value as Record<string, unknown>;
}

function requiredRecord(value: Record<string, unknown>, key: string, path: string): Record<string, unknown> {
  return asRecord(value[key], `${path}.${key}`);
}

function positiveInt(value: Record<string, unknown>, key: string, path: string): number {
  const raw = value[key];
  if (!Number.isSafeInteger(raw) || Number(raw) <= 0) throw new Error(`${path}.${key} must be a positive integer`);
  return Number(raw);
}

function powerShellSingleQuote(value: string): string {
  return `'${value.replace(/'/g, "''")}'`;
}
