import { describe, expect, it, vi } from "vitest";
import { createPermissionApi } from "../permissionApi";
import {
  isPermissionDetail,
  isSavePermissionsRequest,
} from "../permissionTypes";

const detail = {
  documentId: "3",
  sourceDocumentId: "3",
  inherited: false,
  visibilityType: "CUSTOM",
  documentRowVersion: 2,
  entries: [{
    id: "11",
    subjectType: "ORG",
    subjectId: "2",
    subjectName: "通信部",
    canView: true,
    canDownload: true,
    canEdit: false,
    canManagePermission: false,
    canDelete: false,
  }],
} as const;

const ok = (data: unknown) => ({
  data,
  message: "success",
  requestId: "permission-request-id",
  httpStatus: 200,
  headers: new Headers(),
});

describe("F6 permission API and DTO contract", () => {
  it("uses the same canonical permission path for GET and PUT", async () => {
    const client = {
      get: vi.fn().mockResolvedValue(ok(detail)),
      put: vi.fn().mockResolvedValue(ok(detail)),
    };
    const api = createPermissionApi(client);
    await api.get("3");
    await api.save("3", {
      visibilityType: "CUSTOM",
      documentRowVersion: 2,
      entries: [{
        subjectType: "ORG",
        subjectId: "2",
        canView: true,
        canDownload: true,
        canEdit: false,
        canManagePermission: false,
        canDelete: false,
      }],
    });
    expect(client.get).toHaveBeenCalledWith(
      "documents/3/permissions",
      { signal: undefined },
    );
    expect(client.put.mock.calls[0][0]).toBe("documents/3/permissions");
    expect(client.put.mock.calls[0][0]).not.toContain("/api/v1");
  });

  it("preserves requestId on successful parsing", async () => {
    const api = createPermissionApi({
      get: vi.fn().mockResolvedValue(ok(detail)),
      put: vi.fn(),
    });
    await expect(api.get("3")).resolves.toMatchObject({
      requestId: "permission-request-id",
    });
  });

  it("rejects number document IDs", async () => {
    const client = { get: vi.fn(), put: vi.fn() };
    await expect(createPermissionApi(client).get(3 as unknown as string))
      .rejects.toThrow("字符串");
    expect(client.get).not.toHaveBeenCalled();
  });

  it("rejects unknown response fields and keeps requestId", async () => {
    const client = {
      get: vi.fn().mockResolvedValue(ok({ ...detail, permissionSummary: {} })),
      put: vi.fn(),
    };
    await expect(createPermissionApi(client).get("3"))
      .rejects.toMatchObject({
        code: "INTERNAL_ERROR",
        requestId: "permission-request-id",
      });
  });

  it("strictly validates inherited permission details", () => {
    expect(isPermissionDetail(detail)).toBe(true);
    expect(isPermissionDetail({
      ...detail,
      documentId: 3,
    })).toBe(false);
    expect(isPermissionDetail({
      ...detail,
      visibilityType: "PRIVATE",
    })).toBe(false);
    expect(isPermissionDetail({
      ...detail,
      source_document_id: "3",
    })).toBe(false);
  });

  it("requires all five actions to be booleans", () => {
    const entry = detail.entries[0];
    expect(isPermissionDetail({
      ...detail,
      entries: [{ ...entry, canDelete: undefined }],
    })).toBe(false);
    expect(isPermissionDetail({
      ...detail,
      entries: [{ ...entry, canView: 1 }],
    })).toBe(false);
    expect(isPermissionDetail({
      ...detail,
      entries: [{ ...entry, canDownload: "true" }],
    })).toBe(false);
  });

  it("rejects save entries containing id or subjectName", () => {
    expect(isSavePermissionsRequest({
      visibilityType: "CUSTOM",
      documentRowVersion: 2,
      entries: [{
        subjectType: "ORG",
        subjectId: "2",
        subjectName: "通信部",
        canView: true,
        canDownload: false,
        canEdit: false,
        canManagePermission: false,
        canDelete: false,
      }],
    })).toBe(false);
  });

  it("enforces visibility-specific entry rules", () => {
    const org = {
      subjectType: "ORG",
      subjectId: "2",
      canView: true,
      canDownload: false,
      canEdit: false,
      canManagePermission: false,
      canDelete: false,
    };
    const user = { ...org, subjectType: "USER", subjectId: "3" };
    expect(isSavePermissionsRequest({
      visibilityType: "ALL_AUTHENTICATED",
      documentRowVersion: 1,
      entries: [],
    })).toBe(true);
    expect(isSavePermissionsRequest({
      visibilityType: "ALL_AUTHENTICATED",
      documentRowVersion: 1,
      entries: [org],
    })).toBe(false);
    expect(isSavePermissionsRequest({
      visibilityType: "ORGANIZATION",
      documentRowVersion: 1,
      entries: [org],
    })).toBe(true);
    expect(isSavePermissionsRequest({
      visibilityType: "ORGANIZATION",
      documentRowVersion: 1,
      entries: [user],
    })).toBe(false);
    expect(isSavePermissionsRequest({
      visibilityType: "CUSTOM",
      documentRowVersion: 1,
      entries: [org, user],
    })).toBe(true);
  });
});
