import { test, expect } from "../fixtures/role-management";
import { useActor } from "../fixtures/user";
import { RoleCreateFormPage } from "../pages/role/role-create-form";
import { RoleDetailPage } from "../pages/role/role-detail";
import { RoleEditFormPage } from "../pages/role/role-edit-form";
import { RoleListPage } from "../pages/role/role-list";
import { UserDetailPage } from "../pages/user/user-detail";
import { createRole } from "../utils/role-factory";
import { createUser } from "../utils/user-factory";

const USER_PERMISSION = "user-management:user";
const ROLE_PERMISSION = "user-management:role";
const ROLE_ASSIGNMENT_PERMISSION = "user-management:roleAssignment";

test.describe("user--create-role", () => {
  useActor(test, "user");

  test("Create a role with a unique name and one or more permissions", async ({ page }) => {
    const listPage = new RoleListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new RoleCreateFormPage(page);
    const roleName = `E2E Role ${Date.now()}`;
    await formPage.fill({ name: roleName });
    await formPage.permissionOption(ROLE_PERMISSION).click();
    await formPage.submitButton.click();
    await page.waitForURL("**/user-management/role");

    await expect(listPage.heading).toBeVisible();
  });

  test("Duplicate role name is rejected with an error", async ({ page, RolePermissionRole }) => {
    const listPage = new RoleListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new RoleCreateFormPage(page);
    await formPage.fill({ name: RolePermissionRole.name });
    await formPage.permissionOption(ROLE_PERMISSION).click();
    await formPage.submitButton.click();

    await expect(page.locator("body")).toContainText(/already exists|duplicate|error/i);
  });

  test("Submission with a missing role name is blocked by validation", async ({ page }) => {
    const listPage = new RoleListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new RoleCreateFormPage(page);
    await formPage.permissionOption(ROLE_PERMISSION).click();
    await formPage.submitButton.click();

    await expect(page.getByText(/required|cannot be empty/i)).toBeVisible();
  });
});

test.describe("user--assign-role-to-user", () => {
  useActor(test, "user");

  test("Assign a role that is not yet assigned to the user", async ({
    page,
    UserPermissionRole,
  }) => {
    const targetUser = await createUser({
      name: `Assignable User ${Date.now()}`,
      email: `assignable-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);
    await page.reload();
    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).check();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();

    await expect(page.locator("body")).toContainText(/roles updated successfully/i);
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();
  });

  test("Saving role assignments without changes leaves the user's roles unchanged", async ({
    page,
    UserPermissionRole,
  }) => {
    const targetUser = await createUser({
      name: `Sticky User ${Date.now()}`,
      email: `sticky-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);

    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).check();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();

    await detailPage.manageRolesButton.click();
    await expect(detailPage.roleCheckbox(UserPermissionRole.name)).toBeChecked();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();

    await expect(page.locator("body")).toContainText(/roles updated successfully/i);
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();
  });
});

test.describe("user--remove-role-from-user", () => {
  useActor(test, "user");

  test("Remove an assigned role from a user", async ({ page, UserPermissionRole }) => {
    const targetUser = await createUser({
      name: `Removable User ${Date.now()}`,
      email: `removable-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);

    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).check();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();

    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).uncheck();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();

    await expect(page.locator("body")).toContainText(/roles updated successfully/i);
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeHidden();
  });

  test("Cancelling the confirmation leaves the role assignment unchanged", async ({
    page,
    UserPermissionRole,
  }) => {
    const targetUser = await createUser({
      name: `Persistent User ${Date.now()}`,
      email: `persistent-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);

    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).check();
    await detailPage.saveRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();
    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();

    await detailPage.manageRolesButton.click();
    await detailPage.roleCheckbox(UserPermissionRole.name).uncheck();
    await detailPage.cancelRolesButton.click();
    await expect(detailPage.manageRolesDialog).toBeHidden();

    await expect(detailPage.assignedRole(UserPermissionRole.name)).toBeVisible();
  });
});

test.describe("user--update-role-permissions", () => {
  useActor(test, "user");

  test("Add one or more permissions to an existing role", async ({ page, UserPermissionRole }) => {
    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(UserPermissionRole.roleId);
    await detailPage.editButton.click();

    const editForm = new RoleEditFormPage(page);
    await editForm.permissionOption(ROLE_PERMISSION).click();
    await editForm.submitButton.click();
    await page.waitForURL(`**/user-management/role/${UserPermissionRole.roleId}`);

    await expect(page.getByText(ROLE_PERMISSION, { exact: true })).toBeVisible();
  });

  test("Remove one or more permissions from an existing role", async ({ page }) => {
    const role = await createRole({
      name: `Two Perm Role ${Date.now()}`,
      permissions: [USER_PERMISSION, ROLE_PERMISSION],
    });

    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(role.roleId);
    await detailPage.editButton.click();

    const editForm = new RoleEditFormPage(page);
    await editForm.permissionOption(USER_PERMISSION).click();
    await editForm.submitButton.click();
    await page.waitForURL(`**/user-management/role/${role.roleId}`);

    await expect(page.getByText(ROLE_PERMISSION, { exact: true })).toBeVisible();
    await expect(page.getByText(USER_PERMISSION, { exact: true })).toHaveCount(0);
  });

  test("Submission with no permissions selected is blocked by validation", async ({
    page,
    RoleAssignmentPermissionRole,
  }) => {
    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(RoleAssignmentPermissionRole.roleId);
    await detailPage.editButton.click();

    const editForm = new RoleEditFormPage(page);
    await editForm.permissionOption(ROLE_ASSIGNMENT_PERMISSION).click();
    await editForm.submitButton.click();

    await expect(page.locator("body")).toContainText(/at least one permission must be selected/i);
  });
});

test.describe("user--toggle-role-status", () => {
  useActor(test, "user");

  test("Deactivate an ACTIVE role with no active user assignments", async ({ page }) => {
    const role = await createRole({
      name: `Deactivatable Role ${Date.now()}`,
      permissions: [ROLE_PERMISSION],
    });

    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(role.roleId);
    await detailPage.deactivateButton.click();

    await expect(page.getByText(/inactive/i)).toBeVisible();
  });

  test("Reactivate an INACTIVE role", async ({ page }) => {
    const role = await createRole({
      name: `Reactivatable Role ${Date.now()}`,
      permissions: [ROLE_PERMISSION],
    });

    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(role.roleId);
    await detailPage.deactivateButton.click();
    await expect(page.getByText(/inactive/i)).toBeVisible();

    await detailPage.reactivateButton.click();
    await expect(page.getByText(/active/i).first()).toBeVisible();
  });

  test("Cannot deactivate a role that still has active user assignments", async ({ page }) => {
    const role = await createRole({
      name: `Assigned Role ${Date.now()}`,
      permissions: [ROLE_PERMISSION],
    });

    await createUser({
      name: `Assigned User ${Date.now()}`,
      email: `assigned-role-${Date.now()}@example.com`,
      permissions: [ROLE_PERMISSION],
    });

    const detailPage = new RoleDetailPage(page);
    await detailPage.goto(role.roleId);
    await detailPage.deactivateButton.click();

    await expect(page.locator("body")).toContainText(/error|cannot|assigned|active/i);
  });
});
