import { describe, test, expect } from "bun:test";
import UserController from "../../../src/controllers/UserController";
import { buildMockUser } from "../../setup";

describe("UserController", () => {
  // -------------------------------------------------------------------
  // Constructor
  // -------------------------------------------------------------------
  describe("constructor", () => {
    test("sets all public properties", () => {
      const ctrl = new UserController(buildMockUser());
      expect(ctrl.id).toBe("user-1");
      expect(ctrl.name).toBe("Test User");
      expect(ctrl.login).toBe("test@example.com");
      expect(ctrl.email).toBe("test@example.com");
      expect(ctrl.image).toBeNull();
      expect(ctrl.cwIdentifier).toBeNull();
    });

    test("sets cwIdentifier when provided", () => {
      const ctrl = new UserController(
        buildMockUser({ cwIdentifier: "jroberts" }),
      );
      expect(ctrl.cwIdentifier).toBe("jroberts");
    });

    test("sets timestamps", () => {
      const ctrl = new UserController(buildMockUser());
      expect(ctrl.createdAt).toBeInstanceOf(Date);
      expect(ctrl.updatedAt).toBeInstanceOf(Date);
    });

    test("builds roles collection", () => {
      const mockRole = {
        id: "role-1",
        title: "Admin",
        moniker: "admin",
        permissions: "tok",
        createdAt: new Date(),
        updatedAt: new Date(),
      };
      const ctrl = new UserController(buildMockUser({ roles: [mockRole] }));
      // _roles is private, but we can verify via toJson
      const json = ctrl.toJson();
      expect(json.roles).toContain("admin");
    });
  });

  // -------------------------------------------------------------------
  // toJson
  // -------------------------------------------------------------------
  describe("toJson()", () => {
    test("returns full JSON by default", () => {
      const ctrl = new UserController(buildMockUser());
      const json = ctrl.toJson();
      expect(json.id).toBe("user-1");
      expect(json.name).toBe("Test User");
      expect(json.login).toBe("test@example.com");
      expect(json.email).toBe("test@example.com");
      expect(json.image).toBeNull();
      expect(json.createdAt).toBeDefined();
      expect(json.updatedAt).toBeDefined();
    });

    test("safeReturn hides sensitive fields", () => {
      const ctrl = new UserController(buildMockUser());
      const json = ctrl.toJson({ safeReturn: true });
      expect(json.id).toBe("user-1");
      expect(json.name).toBe("Test User");
      expect(json.login).toBeUndefined();
      expect(json.email).toBeUndefined();
      expect(json.cwIdentifier).toBeUndefined();
      expect(json.roles).toBeUndefined();
      expect(json.permissions).toBeUndefined();
    });

    test("cwIdentifier included in full JSON", () => {
      const ctrl = new UserController(
        buildMockUser({ cwIdentifier: "jroberts" }),
      );
      const json = ctrl.toJson();
      expect(json.cwIdentifier).toBe("jroberts");
    });

    test("roles is undefined when user has no roles", () => {
      const ctrl = new UserController(buildMockUser({ roles: [] }));
      const json = ctrl.toJson();
      // _roles.size == 0, so roles is undefined
      expect(json.roles).toBeUndefined();
    });

    test("roles returns monikers when present", () => {
      const mockRoles = [
        {
          id: "r1",
          title: "Admin",
          moniker: "admin",
          permissions: "t",
          createdAt: new Date(),
          updatedAt: new Date(),
        },
        {
          id: "r2",
          title: "User",
          moniker: "user",
          permissions: "t",
          createdAt: new Date(),
          updatedAt: new Date(),
        },
      ];
      const ctrl = new UserController(buildMockUser({ roles: mockRoles }));
      const json = ctrl.toJson();
      expect(json.roles).toHaveLength(2);
      expect(json.roles).toContain("admin");
      expect(json.roles).toContain("user");
    });

    test("permissions returns empty array when user has no permissions token", () => {
      const ctrl = new UserController(buildMockUser({ permissions: null }));
      const json = ctrl.toJson();
      expect(json.permissions).toEqual([]);
    });
  });

  // -------------------------------------------------------------------
  // readPermissions
  // -------------------------------------------------------------------
  describe("readPermissions()", () => {
    test("returns empty array when permissions is null", () => {
      const ctrl = new UserController(buildMockUser({ permissions: null }));
      expect(ctrl.readPermissions()).toEqual([]);
    });
  });
});
