/**
 * Workspace Access Integration Tests
 *
 * Tests that workspace-scoped federation endpoints enforce workspace access.
 */

import { describe, it, expect, beforeEach, vi } from "vitest";
import { WorkspaceGuard } from "../common/guards/workspace.guard";
import { PrismaService } from "../prisma/prisma.service";
import { ForbiddenException } from "@nestjs/common";
import type { AuthenticatedRequest } from "../common/types/user.types";

describe("Workspace Access Control - Federation", () => {
  let prismaService: PrismaService;
  let workspaceGuard: WorkspaceGuard;

  beforeEach(() => {
    const mockPrismaService = {
      workspaceMember: {
        findUnique: vi.fn(),
      },
    };

    prismaService = mockPrismaService as unknown as PrismaService;
    workspaceGuard = new WorkspaceGuard(prismaService);
  });

  describe("Workspace membership verification", () => {
    it("should allow access when user is workspace member", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
          workspaceId: "workspace-456",
        },
        headers: {
          "x-workspace-id": "workspace-456",
        },
        params: {},
        body: {},
      } as AuthenticatedRequest;

      // Mock workspace membership exists
      vi.spyOn(prismaService.workspaceMember, "findUnique").mockResolvedValue({
        workspaceId: "workspace-456",
        userId: "user-123",
        role: "ADMIN",
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      const canActivate = await workspaceGuard.canActivate({
        switchToHttp: () => ({
          getRequest: () => mockRequest,
        }),
      } as any);

      expect(canActivate).toBe(true);
    });

    it("should deny access when user is not workspace member", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
        },
        headers: {
          "x-workspace-id": "workspace-999",
        },
        params: {},
        body: {},
      } as AuthenticatedRequest;

      // Mock workspace membership does not exist
      vi.spyOn(prismaService.workspaceMember, "findUnique").mockResolvedValue(null);

      await expect(
        workspaceGuard.canActivate({
          switchToHttp: () => ({
            getRequest: () => mockRequest,
          }),
        } as any)
      ).rejects.toThrow(ForbiddenException);
    });

    it("should deny access when workspace ID is missing", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
        },
        headers: {},
        params: {},
        body: {},
      } as AuthenticatedRequest;

      await expect(
        workspaceGuard.canActivate({
          switchToHttp: () => ({
            getRequest: () => mockRequest,
          }),
        } as any)
      ).rejects.toThrow("Workspace ID is required");
    });

    it("should check workspace ID from URL parameter", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
        },
        headers: {},
        params: {
          workspaceId: "workspace-789",
        },
      } as any;

      vi.spyOn(prismaService.workspaceMember, "findUnique").mockResolvedValue({
        workspaceId: "workspace-789",
        userId: "user-123",
        role: "MEMBER",
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      const canActivate = await workspaceGuard.canActivate({
        switchToHttp: () => ({
          getRequest: () => mockRequest,
        }),
      } as any);

      expect(canActivate).toBe(true);
      expect(prismaService.workspaceMember.findUnique).toHaveBeenCalledWith({
        where: {
          workspaceId_userId: {
            workspaceId: "workspace-789",
            userId: "user-123",
          },
        },
      });
    });

    it("should check workspace ID from request body", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
        },
        headers: {},
        params: {},
        body: {
          workspaceId: "workspace-111",
        },
      } as any;

      vi.spyOn(prismaService.workspaceMember, "findUnique").mockResolvedValue({
        workspaceId: "workspace-111",
        userId: "user-123",
        role: "ADMIN",
        createdAt: new Date(),
        updatedAt: new Date(),
      } as any);

      const canActivate = await workspaceGuard.canActivate({
        switchToHttp: () => ({
          getRequest: () => mockRequest,
        }),
      } as any);

      expect(canActivate).toBe(true);
    });
  });

  describe("Workspace isolation", () => {
    it("should prevent cross-workspace access", async () => {
      const mockRequest: Partial<AuthenticatedRequest> = {
        user: {
          id: "user-123",
          email: "test@example.com",
        },
        headers: {
          "x-workspace-id": "workspace-attacker",
        },
        params: {},
        body: {},
      } as AuthenticatedRequest;

      // User is NOT a member of the requested workspace
      vi.spyOn(prismaService.workspaceMember, "findUnique").mockResolvedValue(null);

      await expect(
        workspaceGuard.canActivate({
          switchToHttp: () => ({
            getRequest: () => mockRequest,
          }),
        } as any)
      ).rejects.toThrow(ForbiddenException);
    });
  });
});
