import { AssistantApprovalStatus, type Prisma } from "@capakraken/db";
import { SystemRole } from "@capakraken/shared";
import { describe, expect, it, vi } from "vitest";
import { assistantRouter } from "../router/assistant.js";
import { createCallerFactory } from "../trpc.js";

const createCaller = createCallerFactory(assistantRouter);

function createContext(
  db: Record<string, unknown>,
  options: {
    role?: SystemRole;
    session?: boolean;
  } = {},
) {
  const { role = SystemRole.USER, session = true } = options;

  return {
    session: session
      ? {
          user: { email: "user@example.com", name: "User", image: null },
          expires: "2099-01-01T00:00:00.000Z",
        }
      : null,
    db: db as never,
    dbUser: session
      ? {
          id: role === SystemRole.ADMIN ? "user_admin" : "user_1",
          systemRole: role,
          permissionOverrides: null,
        }
      : null,
  };
}

describe("assistant router authorization", () => {
  it("requires authentication for pending approval lists", async () => {
    const updateMany = vi.fn();
    const findMany = vi.fn();
    const caller = createCaller(createContext({
      assistantApproval: {
        updateMany,
        findMany,
      },
    }, { session: false }));

    await expect(caller.listPendingApprovals()).rejects.toMatchObject({
      code: "UNAUTHORIZED",
      message: "Authentication required",
    });

    expect(updateMany).not.toHaveBeenCalled();
    expect(findMany).not.toHaveBeenCalled();
  });

  it("lists only pending approvals for the current user", async () => {
    const createdAt = new Date("2026-03-30T10:00:00.000Z");
    const expiresAt = new Date("2026-03-30T10:15:00.000Z");
    const updateMany = vi.fn().mockResolvedValue({ count: 0 });
    const findMany = vi.fn().mockResolvedValue([
      {
        id: "approval_1",
        userId: "user_1",
        conversationId: "conv_1",
        toolName: "create_project",
        toolArguments: "{\"name\":\"Apollo\"}",
        summary: "create project Apollo",
        status: AssistantApprovalStatus.PENDING,
        createdAt,
        expiresAt,
      },
    ] satisfies Array<Prisma.AssistantApprovalGetPayload<Record<string, never>>>);
    const caller = createCaller(createContext({
      assistantApproval: {
        updateMany,
        findMany,
      },
    }));

    const result = await caller.listPendingApprovals();

    expect(result).toEqual([
      {
        id: "approval_1",
        status: "pending",
        conversationId: "conv_1",
        toolName: "create_project",
        summary: "create project Apollo",
        createdAt: createdAt.toISOString(),
        expiresAt: expiresAt.toISOString(),
      },
    ]);
    expect(updateMany).toHaveBeenCalledWith({
      where: {
        userId: "user_1",
        status: AssistantApprovalStatus.PENDING,
        expiresAt: { lte: expect.any(Date) },
      },
      data: {
        status: AssistantApprovalStatus.EXPIRED,
      },
    });
    expect(findMany).toHaveBeenCalledWith({
      where: {
        userId: "user_1",
        status: AssistantApprovalStatus.PENDING,
        expiresAt: { gt: expect.any(Date) },
      },
      orderBy: { createdAt: "desc" },
    });
  });

  it("requires authentication before starting assistant chat", async () => {
    const findUnique = vi.fn();
    const caller = createCaller(createContext({
      systemSettings: {
        findUnique,
      },
    }, { session: false }));

    await expect(caller.chat({
      messages: [{ role: "user", content: "Hallo" }],
    })).rejects.toMatchObject({
      code: "UNAUTHORIZED",
      message: "Authentication required",
    });

    expect(findUnique).not.toHaveBeenCalled();
  });
});
