import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { ExecutionContext, ForbiddenException } from "@nestjs/common";
import { AdminGuard } from "./admin.guard";

describe("AdminGuard", () => {
  const originalEnv = process.env.SYSTEM_ADMIN_IDS;

  afterEach(() => {
    // Restore original environment
    if (originalEnv !== undefined) {
      process.env.SYSTEM_ADMIN_IDS = originalEnv;
    } else {
      delete process.env.SYSTEM_ADMIN_IDS;
    }
    vi.clearAllMocks();
  });

  const createMockExecutionContext = (user: { id: string } | undefined): ExecutionContext => {
    const mockRequest = {
      user,
    };

    return {
      switchToHttp: () => ({
        getRequest: () => mockRequest,
      }),
    } as ExecutionContext;
  };

  describe("constructor", () => {
    it("should parse system admin IDs from environment variable", () => {
      process.env.SYSTEM_ADMIN_IDS = "admin-1,admin-2,admin-3";
      const guard = new AdminGuard();

      expect(guard.isSystemAdmin("admin-1")).toBe(true);
      expect(guard.isSystemAdmin("admin-2")).toBe(true);
      expect(guard.isSystemAdmin("admin-3")).toBe(true);
    });

    it("should handle whitespace in admin IDs", () => {
      process.env.SYSTEM_ADMIN_IDS = " admin-1 , admin-2 , admin-3 ";
      const guard = new AdminGuard();

      expect(guard.isSystemAdmin("admin-1")).toBe(true);
      expect(guard.isSystemAdmin("admin-2")).toBe(true);
      expect(guard.isSystemAdmin("admin-3")).toBe(true);
    });

    it("should handle empty environment variable", () => {
      process.env.SYSTEM_ADMIN_IDS = "";
      const guard = new AdminGuard();

      expect(guard.isSystemAdmin("any-user")).toBe(false);
    });

    it("should handle missing environment variable", () => {
      delete process.env.SYSTEM_ADMIN_IDS;
      const guard = new AdminGuard();

      expect(guard.isSystemAdmin("any-user")).toBe(false);
    });

    it("should handle single admin ID", () => {
      process.env.SYSTEM_ADMIN_IDS = "single-admin";
      const guard = new AdminGuard();

      expect(guard.isSystemAdmin("single-admin")).toBe(true);
    });
  });

  describe("isSystemAdmin", () => {
    let guard: AdminGuard;

    beforeEach(() => {
      process.env.SYSTEM_ADMIN_IDS = "admin-uuid-1,admin-uuid-2";
      guard = new AdminGuard();
    });

    it("should return true for configured system admin", () => {
      expect(guard.isSystemAdmin("admin-uuid-1")).toBe(true);
      expect(guard.isSystemAdmin("admin-uuid-2")).toBe(true);
    });

    it("should return false for non-admin user", () => {
      expect(guard.isSystemAdmin("regular-user-id")).toBe(false);
    });

    it("should return false for empty string", () => {
      expect(guard.isSystemAdmin("")).toBe(false);
    });
  });

  describe("canActivate", () => {
    let guard: AdminGuard;

    beforeEach(() => {
      process.env.SYSTEM_ADMIN_IDS = "admin-uuid-1,admin-uuid-2";
      guard = new AdminGuard();
    });

    it("should return true for system admin user", () => {
      const context = createMockExecutionContext({ id: "admin-uuid-1" });

      const result = guard.canActivate(context);

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

    it("should throw ForbiddenException for non-admin user", () => {
      const context = createMockExecutionContext({ id: "regular-user-id" });

      expect(() => guard.canActivate(context)).toThrow(ForbiddenException);
      expect(() => guard.canActivate(context)).toThrow(
        "This operation requires system administrator privileges"
      );
    });

    it("should throw ForbiddenException when user is not authenticated", () => {
      const context = createMockExecutionContext(undefined);

      expect(() => guard.canActivate(context)).toThrow(ForbiddenException);
      expect(() => guard.canActivate(context)).toThrow("User not authenticated");
    });

    it("should NOT grant admin access based on workspace ownership", () => {
      // This test verifies that workspace ownership alone does not grant admin access
      // The user must be explicitly listed in SYSTEM_ADMIN_IDS
      const workspaceOwnerButNotSystemAdmin = { id: "workspace-owner-id" };
      const context = createMockExecutionContext(workspaceOwnerButNotSystemAdmin);

      expect(() => guard.canActivate(context)).toThrow(ForbiddenException);
      expect(() => guard.canActivate(context)).toThrow(
        "This operation requires system administrator privileges"
      );
    });

    it("should deny access when no system admins are configured", () => {
      process.env.SYSTEM_ADMIN_IDS = "";
      const guardWithNoAdmins = new AdminGuard();

      const context = createMockExecutionContext({ id: "any-user-id" });

      expect(() => guardWithNoAdmins.canActivate(context)).toThrow(ForbiddenException);
    });
  });

  describe("security: workspace ownership vs system admin", () => {
    it("should require explicit system admin configuration, not implicit workspace ownership", () => {
      // Setup: user is NOT in SYSTEM_ADMIN_IDS
      process.env.SYSTEM_ADMIN_IDS = "different-admin-id";
      const guard = new AdminGuard();

      // Even if this user owns workspaces, they should NOT have system admin access
      // because they are not in SYSTEM_ADMIN_IDS
      const context = createMockExecutionContext({ id: "workspace-owner-user-id" });

      expect(() => guard.canActivate(context)).toThrow(ForbiddenException);
    });

    it("should grant access only to users explicitly listed as system admins", () => {
      const adminUserId = "explicitly-configured-admin";
      process.env.SYSTEM_ADMIN_IDS = adminUserId;
      const guard = new AdminGuard();

      const context = createMockExecutionContext({ id: adminUserId });

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