import { describe, expect, it, vi } from "vitest";
import {
  assertCanReadOwnedResource,
  canManageOwnedResourceReads,
  findOwnedReadResourceId,
  resolveOwnedResourceReadFilter,
} from "../router/resource-owned-read-access.js";

function createContext(options: {
  role?: string | null;
  userId?: string | null;
  resourceFindFirst?: ReturnType<typeof vi.fn>;
} = {}) {
  return {
    dbUser: options.userId === null
      ? null
      : {
          id: options.userId ?? "user_1",
          systemRole: options.role ?? "USER",
        },
    db: {
      resource: options.resourceFindFirst
        ? { findFirst: options.resourceFindFirst }
        : {
            findFirst: vi.fn().mockResolvedValue({ id: "res_own" }),
          },
    },
  };
}

describe("resource-owned-read-access", () => {
  it("treats admins and managers as broad readers", () => {
    expect(canManageOwnedResourceReads(createContext({ role: "ADMIN" }))).toBe(true);
    expect(canManageOwnedResourceReads(createContext({ role: "MANAGER" }))).toBe(true);
    expect(canManageOwnedResourceReads(createContext({ role: "USER" }))).toBe(false);
  });

  it("finds the signed-in user's owned resource id", async () => {
    const resourceFindFirst = vi.fn().mockResolvedValue({ id: "res_123" });

    await expect(findOwnedReadResourceId(createContext({ resourceFindFirst }))).resolves.toBe("res_123");
    expect(resourceFindFirst).toHaveBeenCalledWith({
      where: { userId: "user_1" },
      select: { id: true },
    });
  });

  it("scopes regular readers to their own resource filter", async () => {
    await expect(
      resolveOwnedResourceReadFilter(
        createContext({ role: "USER" }),
        undefined,
        "forbidden",
      ),
    ).resolves.toBe("res_own");
  });

  it("preserves the requested filter for managers", async () => {
    await expect(
      resolveOwnedResourceReadFilter(
        createContext({ role: "MANAGER" }),
        "res_other",
        "forbidden",
      ),
    ).resolves.toBe("res_other");
  });

  it("rejects access to another resource for regular readers", async () => {
    await expect(
      assertCanReadOwnedResource(
        createContext({ role: "USER" }),
        "res_other",
        "forbidden",
      ),
    ).rejects.toMatchObject({
      code: "FORBIDDEN",
      message: "forbidden",
    });
  });
});
