import assert from "node:assert/strict";
import test from "node:test";
import type { PermissionsService } from "@gotgenes/pi-permission-system";
import {
  formatSshPermissionInput,
  installSshPermissionIntegration,
  type SshPermissionConnection,
} from "../permission-integration.ts";

function makeService() {
  const formatters = new Map<string, (input: Record<string, unknown>) => string | undefined>();
  const extractors = new Map<string, (input: Record<string, unknown>) => string | undefined>();
  const service = {
    registerToolInputFormatter(name: string, formatter: (input: Record<string, unknown>) => string | undefined) {
      formatters.set(name, formatter);
      return () => formatters.delete(name);
    },
    registerToolAccessExtractor(name: string, extractor: (input: Record<string, unknown>) => string | undefined) {
      extractors.set(name, extractor);
      return () => extractors.delete(name);
    },
  } as unknown as PermissionsService;
  return { service, formatters, extractors };
}

function makePi() {
  const hooks = new Map<string, Array<() => void>>();
  const eventHooks = new Map<string, Array<() => void>>();
  const add = (map: Map<string, Array<() => void>>, name: string, handler: () => void) => {
    map.set(name, [...(map.get(name) ?? []), handler]);
  };
  return {
    api: {
      on: (name: string, handler: () => void) => add(hooks, name, handler),
      events: { on: (name: string, handler: () => void) => add(eventHooks, name, handler) },
    },
    emit: (name: string) => hooks.get(name)?.forEach((handler) => handler()),
    emitEvent: (name: string) => eventHooks.get(name)?.forEach((handler) => handler()),
  };
}

const connection: SshPermissionConnection = {
  remote: "packaging-server",
  port: 2222,
  remoteCwd: "/srv/build",
  remoteHome: "/home/builder",
};

test("formats reviewed connection requests without exposing credentials", () => {
  assert.equal(
    formatSshPermissionInput("ssh_connect", { hostId: "packaging-server", remotePath: "/srv/build" }, connection),
    "SSH target 'packaging-server:2222' in remote cwd '/srv/build'; establish a persistent SSH2 connection",
  );
  assert.equal(
    formatSshPermissionInput("ssh_connect", { hostId: "unknown" }, null),
    "requested imported SSH host 'unknown'; establish a persistent SSH2 connection",
  );
});

test("formats the SSH target and bounded operation details", () => {
  assert.equal(
    formatSshPermissionInput("ssh_read", { path: "src/main.ts", offset: 5, limit: 20 }, connection),
    "SSH target 'packaging-server:2222' in remote cwd '/srv/build'; read remote path '/srv/build/src/main.ts' (requested 'src/main.ts'), offset 5, limit 20",
  );
  assert.equal(
    formatSshPermissionInput("ssh_write", { path: "dist/a.txt", content: "one\ntwo" }, connection),
    "SSH target 'packaging-server:2222' in remote cwd '/srv/build'; write remote path '/srv/build/dist/a.txt' (requested 'dist/a.txt') (2 lines, 7 characters)",
  );
  assert.equal(
    formatSshPermissionInput("ssh_grep", { pattern: "TODO", path: "src", include: "*.ts", limit: 25 }, connection),
    "SSH target 'packaging-server:2222' in remote cwd '/srv/build'; search remote file contents under '/srv/build/src' (requested 'src'), for 'TODO', limit 25, file glob '*.ts'",
  );
  assert.equal(
    formatSshPermissionInput("ssh_cd", { path: "../release" }, connection),
    "SSH target 'packaging-server:2222' in remote cwd '/srv/build'; change the active remote cwd to '/srv/release' (requested '../release')",
  );
  assert.match(
    formatSshPermissionInput("ssh_read", { path: "~/logs/app.log" }, connection),
    /remote path '\/home\/builder\/logs\/app\.log' \(requested '~\/logs\/app\.log'\)/,
  );
});

test("registers previews and disables local path extraction for remote path tools", () => {
  const { service, formatters, extractors } = makeService();
  const pi = makePi();
  const dispose = installSshPermissionIntegration(
    pi.api as never,
    () => connection,
    {
      getPermissionsService: () => service,
      permissionsReadyChannel: "permissions:ready",
      getConnectTarget: () => connection,
    },
  );

  assert.deepEqual([...formatters.keys()], ["ssh_connect", "ssh_cd", "ssh_read", "ssh_write", "ssh_edit", "ssh_find", "ssh_grep", "ssh_bash"]);
  assert.deepEqual([...extractors.keys()], ["ssh_cd", "ssh_read", "ssh_write", "ssh_edit", "ssh_find", "ssh_grep"]);
  assert.equal(extractors.get("ssh_read")?.({ path: "/remote/secret" }), undefined);
  assert.equal(extractors.get("ssh_grep")?.({ path: "/remote/src" }), undefined);
  assert.equal(extractors.get("ssh_cd")?.({ path: "/remote/release" }), undefined);
  assert.match(formatters.get("ssh_bash")?.({ command: "git push" }) ?? "", /packaging-server:2222/);
  assert.match(formatters.get("ssh_connect")?.({ hostId: "packaging-server" }) ?? "", /establish a persistent SSH2 connection/);

  dispose();
  assert.equal(formatters.size, 0);
  assert.equal(extractors.size, 0);
});

test("registers when the permission service becomes ready and cleans up on shutdown", () => {
  const { service, formatters, extractors } = makeService();
  const pi = makePi();
  let published: PermissionsService | undefined;
  installSshPermissionIntegration(pi.api as never, () => connection, {
    getPermissionsService: () => published,
    permissionsReadyChannel: "permissions:ready",
  });
  assert.equal(formatters.size, 0);

  published = service;
  pi.emitEvent("permissions:ready");
  assert.equal(formatters.size, 8);
  assert.equal(extractors.size, 6);

  pi.emit("session_shutdown");
  assert.equal(formatters.size, 0);
  assert.equal(extractors.size, 0);
});
