import { describe, expect, it } from "vitest";
import type { CapabilityRequest } from "@best-agent/protocol";
import { toHistorySafeCapabilityRequest } from "../policy/capability-history.js";
import type { ApprovalCheckpointPayload } from "./checkpoint-codec.js";
import {
  isSameApprovalCheckpointRequest,
  resolveApprovalGrantAction,
  resolvePersistedApprovalGrantAction,
} from "./approval/approval-grant-actions.js";

describe("approval grant action", () => {
  it("uses command-class actions for non-sensitive shell grants", () => {
    const request: CapabilityRequest = {
      argv: ["sh", "-c", "echo secret"],
      cwd: "/workspace",
      group: "shell",
    };

    const action = resolveApprovalGrantAction(request, "shell");

    expect(action).toBe("shell:shell:echo:non-sensitive");
    expect(action).not.toContain("echo secret");
  });

  it("uses command-class actions for non-sensitive extension shell grants", () => {
    const request: CapabilityRequest = {
      argv: ["extension-helper", "short-secret"],
      cwd: "/workspace",
      group: "shell",
    };

    const action = resolveApprovalGrantAction(request, "ext:helper:run");

    expect(action).toBe("shell:extension-helper:non-sensitive");
    expect(action).not.toContain("short-secret");
  });

  it("does not reuse legacy raw shell grant actions", () => {
    const request: CapabilityRequest = {
      argv: ["extension-helper", "short-secret"],
      cwd: "/workspace",
      group: "shell",
    };

    const action = resolvePersistedApprovalGrantAction(
      request,
      "ext:helper:run",
      "extension-helper short-secret",
    );

    expect(action).toBe("shell:extension-helper:non-sensitive");
    expect(action).not.toContain("short-secret");
  });

  it("does not reuse shell persisted grant actions for extension shell requests", () => {
    const request: CapabilityRequest = {
      argv: ["extension-helper", "short-secret"],
      cwd: "/workspace",
      group: "shell",
    };

    const action = resolvePersistedApprovalGrantAction(request, "ext:helper:run", "tool:shell");

    expect(action).toBe("shell:extension-helper:non-sensitive");
    expect(action).not.toBe("tool:shell");
  });

  it("keeps sensitive shell requests on exact digest actions", () => {
    const ordinaryRequest: CapabilityRequest = {
      argv: ["/bin/sh", "-lc", "echo ok"],
      cwd: "/workspace",
      group: "shell",
    };
    const sensitiveRequest: CapabilityRequest = {
      argv: ["/bin/sh", "-lc", 'cat .env 2>/dev/null | grep -v "^#" | sed "s/=.*/=***/"'],
      cwd: "/workspace",
      group: "shell",
    };

    expect(resolveApprovalGrantAction(ordinaryRequest, "shell")).toBe(
      "shell:shell:echo:non-sensitive",
    );
    expect(resolveApprovalGrantAction(sensitiveRequest, "shell")).toMatch(
      /^shell:sensitive:[a-f0-9]{64}$/u,
    );
    expect(resolveApprovalGrantAction(ordinaryRequest, "shell")).not.toBe(
      resolveApprovalGrantAction(sensitiveRequest, "shell"),
    );
    expect(
      resolvePersistedApprovalGrantAction(
        sensitiveRequest,
        "shell",
        resolveApprovalGrantAction(ordinaryRequest, "shell"),
      ),
    ).toBe(resolveApprovalGrantAction(sensitiveRequest, "shell"));
    expect(resolvePersistedApprovalGrantAction(sensitiveRequest, "shell", "tool:shell")).toBe(
      resolveApprovalGrantAction(sensitiveRequest, "shell"),
    );
  });

  it("preserves matching persisted shell grant actions", () => {
    const request: CapabilityRequest = {
      argv: ["extension-helper", "short-secret"],
      cwd: "/workspace",
      group: "shell",
    };
    const action = resolveApprovalGrantAction(request, "ext:helper:run");

    expect(
      resolvePersistedApprovalGrantAction(request, "ext:helper:run", action, "raw-request-digest"),
    ).toBe(action);
  });

  it("does not reuse persisted shell digest actions without raw-request provenance", () => {
    const request: CapabilityRequest = {
      argv: ["extension-helper", "short-secret"],
      cwd: "/workspace",
      group: "shell",
    };
    const action =
      "shell:sensitive:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";

    expect(resolvePersistedApprovalGrantAction(request, "ext:helper:run", action)).toBe(
      resolveApprovalGrantAction(request, "ext:helper:run"),
    );
  });

  it("preserves persisted raw shell approval grant action when checkpoint request is history-safe", () => {
    const request: CapabilityRequest = {
      argv: ["node", "-e", "secret\n".repeat(1_000)],
      cwd: "/workspace",
      group: "shell",
    };
    const action = resolveApprovalGrantAction(request, "ext:helper:run");
    const safeRequest = toHistorySafeCapabilityRequest(request);

    expect(
      resolvePersistedApprovalGrantAction(
        safeRequest,
        "ext:helper:run",
        action,
        "raw-request-digest",
      ),
    ).toBe(action);
  });

  it("keeps ordinary non-shell grants identity-scoped", () => {
    expect(
      resolveApprovalGrantAction({
        action: "read",
        group: "filesystem",
        path: "/workspace/package.json",
      }),
    ).toBe("read:/workspace/package.json");
    expect(resolveApprovalGrantAction({ group: "network", host: "api.example.com" })).toBe(
      "api.example.com",
    );
  });

  it("uses digest actions for secret-like non-shell grants", () => {
    const networkAction = resolveApprovalGrantAction({
      group: "network",
      host: "api.example.com?token=sk-12345678",
    });
    const filesystemAction = resolveApprovalGrantAction({
      action: "read",
      group: "filesystem",
      path: "/tmp/sk-12345678",
    });

    expect(networkAction).toMatch(/^network:network:[a-f0-9]{64}$/u);
    expect(networkAction).not.toContain("sk-12345678");
    expect(filesystemAction).toMatch(/^filesystem:filesystem:[a-f0-9]{64}$/u);
    expect(filesystemAction).not.toContain("sk-12345678");
  });

  it("does not reuse legacy raw secret-like non-shell grant actions", () => {
    const request: CapabilityRequest = {
      group: "network",
      host: "api.example.com?token=sk-12345678",
    };

    const action = resolvePersistedApprovalGrantAction(
      request,
      undefined,
      "api.example.com?token=sk-12345678",
    );

    expect(action).toMatch(/^network:network:[a-f0-9]{64}$/u);
    expect(action).not.toContain("sk-12345678");
  });

  it("preserves persisted non-shell digest actions when checkpoint request is history-safe", () => {
    const request: CapabilityRequest = {
      action: "read",
      group: "filesystem",
      path: "/tmp/sk-12345678",
    };
    const action = resolveApprovalGrantAction(request);
    const safeRequest = toHistorySafeCapabilityRequest(request);

    expect(
      resolvePersistedApprovalGrantAction(safeRequest, undefined, action, "raw-request-digest"),
    ).toBe(action);
  });

  it("matches resolved non-shell approval checkpoints after request redaction", () => {
    const request: CapabilityRequest = {
      group: "network",
      host: "api.example.com?token=sk-12345678",
    };
    const checkpoint = {
      approvalGrantAction: resolveApprovalGrantAction(request),
      approvalGrantActionSource: "raw-request-digest",
      kind: "approval",
      request: toHistorySafeCapabilityRequest(request),
      resolution: { decision: "allow", scope: "once" },
    } as ApprovalCheckpointPayload;

    expect(JSON.stringify(checkpoint.request)).not.toContain("sk-12345678");
    expect(isSameApprovalCheckpointRequest(checkpoint, request)).toBe(true);
  });

  it("matches resolved shell approval checkpoints after request redaction", () => {
    const request: CapabilityRequest = {
      argv: ["curl", "-H", "Authorization: Bearer sk-1234567890abcdef", "https://api.example.com"],
      cwd: "/repo",
      group: "shell",
    };
    const checkpoint = {
      approvalGrantAction: resolveApprovalGrantAction(request, "shell"),
      approvalGrantActionSource: "raw-request-digest",
      kind: "approval",
      request: toHistorySafeCapabilityRequest(request),
      resolution: { decision: "allow", scope: "once" },
      toolName: "shell",
    } as ApprovalCheckpointPayload;

    expect(isSameApprovalCheckpointRequest(checkpoint, request)).toBe(true);
  });
});
