import { ACTOR_PERMISSIONS, useActor } from "../fixtures/user";
import { test, expect } from "../fixtures/user-lifecycle";
import { LoginPage } from "../pages/auth/login";
import { MyProfilePage } from "../pages/user/my-profile";
import { MyProfileEditFormPage } from "../pages/user/my-profile-edit-form";
import { UserCreateFormPage } from "../pages/user/user-create-form";
import { UserDetailPage } from "../pages/user/user-detail";
import { UserEditFormPage } from "../pages/user/user-edit-form";
import { UserListPage } from "../pages/user/user-list";
import { createUser } from "../utils/user-factory";

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

  test("Create user with all required fields and one or more roles; initial password is displayed in a dialog", async ({
    page,
    SelectableRole,
  }) => {
    const formPage = new UserCreateFormPage(page);
    const email = `e2e-create-${Date.now()}@example.com`;
    await formPage.goto();
    await page.reload();
    await expect(formPage.nameInput).toBeVisible();
    await formPage.fill({ name: "New E2E User", email });
    await formPage.roleSelect.click();
    const option = formPage.roleOption(SelectableRole.name);
    await option.waitFor({ state: "visible" });
    // Pick via Select typeahead — clicking can miss when a long option list
    // pushes the target outside the popover's viewport.
    await page.keyboard.type(SelectableRole.name);
    await page.keyboard.press("Enter");
    await page.keyboard.press("Escape");
    await formPage.submitButton.click();

    await expect(formPage.successDialog).toBeVisible();
    await expect(formPage.successDialog).toContainText(/password/i);
  });

  test("Create user with no roles assigned; user is created and roles can be assigned later", async ({
    page,
  }) => {
    const listPage = new UserListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new UserCreateFormPage(page);
    const userName = `No Role User ${Date.now()}`;
    await formPage.fill({ name: userName, email: `e2e-norole-${Date.now()}@example.com` });
    await formPage.submitButton.click();
    await expect(formPage.successDialog).toBeVisible();
    await formPage.doneButton.click();

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

  test("Duplicate email address is rejected with an error", async ({ page }) => {
    const listPage = new UserListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new UserCreateFormPage(page);
    const email = `e2e-dup-${Date.now()}@example.com`;
    await formPage.fill({ name: "First User", email });
    await formPage.submitButton.click();
    await expect(formPage.successDialog).toBeVisible();
    await formPage.doneButton.click();

    await listPage.goto();
    await listPage.createButton.click();
    await formPage.fill({ name: "Duplicate User", email });
    await formPage.submitButton.click();

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

  test("Submission with missing required fields is blocked by validation", async ({ page }) => {
    const listPage = new UserListPage(page);
    await listPage.goto();
    await listPage.createButton.click();

    const formPage = new UserCreateFormPage(page);
    await formPage.submitButton.click();

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

test.describe("user--browse-user-list", () => {
  useActor(test, "user");

  test("View the full list of users with name, email, role, and status columns", async ({
    page,
  }) => {
    const listPage = new UserListPage(page);
    await listPage.goto();
    await expect(listPage.heading).toBeVisible();
    await expect(listPage.table).toBeVisible();
  });
});

test.describe("user--view-user-detail", () => {
  useActor(test, "user");

  test("View full profile details of another user including name, email, status, and assigned roles", async ({
    page,
  }) => {
    const targetUser = await createUser({
      name: `Viewable User ${Date.now()}`,
      email: `viewable-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);
    await expect(detailPage.heading).toBeVisible();
    await expect(detailPage.statusBadge).toBeVisible();
  });
});

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

  test("Update another user's name", async ({ page }) => {
    const targetUser = await createUser({
      name: `Editable User ${Date.now()}`,
      email: `editable-name-${Date.now()}@example.com`,
    });

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

    const editForm = new UserEditFormPage(page);
    const newName = `Updated Name ${Date.now()}`;
    await editForm.nameInput.clear();
    await editForm.nameInput.fill(newName);
    await editForm.submitButton.click();

    await expect(page.getByText(newName)).toBeVisible();
  });

  test("Update another user's email address", async ({ page }) => {
    const targetUser = await createUser({
      name: `Editable Email User ${Date.now()}`,
      email: `editable-email-${Date.now()}@example.com`,
    });

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

    const editForm = new UserEditFormPage(page);
    const newEmail = `updated-${Date.now()}@example.com`;
    await editForm.emailInput.clear();
    await editForm.emailInput.fill(newEmail);
    await editForm.submitButton.click();

    await expect(page.getByText(newEmail)).toBeVisible();
  });

  test("Duplicate email address is rejected with an error", async ({ page, user }) => {
    const targetUser = await createUser({
      name: `Dup Email Target ${Date.now()}`,
      email: `dup-target-${Date.now()}@example.com`,
    });

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

    const editForm = new UserEditFormPage(page);
    await editForm.emailInput.clear();
    await editForm.emailInput.fill(user.email);
    await editForm.submitButton.click();

    await expect(page.getByText(/error|already|exists|duplicate/i)).toBeVisible();
  });

  test("Submission with missing required fields is blocked by validation", async ({ page }) => {
    const targetUser = await createUser({
      name: `Validation User ${Date.now()}`,
      email: `validation-${Date.now()}@example.com`,
    });

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

    const editForm = new UserEditFormPage(page);
    await editForm.nameInput.clear();
    await editForm.submitButton.click();

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

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

  test("Deactivate an ACTIVE user account", async ({ page }) => {
    const targetUser = await createUser({
      name: `Deactivatable User ${Date.now()}`,
      email: `deactivatable-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);
    await expect(detailPage.statusBadge).toContainText(/active/i);
    await detailPage.deactivateButton.click();

    await expect(detailPage.statusBadge).toContainText(/inactive/i);
  });

  test("Reactivate an INACTIVE user account", async ({ page }) => {
    const targetUser = await createUser({
      name: `Reactivatable User ${Date.now()}`,
      email: `reactivatable-${Date.now()}@example.com`,
    });

    const detailPage = new UserDetailPage(page);
    await detailPage.goto(targetUser.userId);
    await detailPage.deactivateButton.click();
    await expect(detailPage.statusBadge).toContainText(/inactive/i);

    await detailPage.activateButton.click();
    await expect(detailPage.statusBadge).toContainText(/active/i);
  });

  test("Cannot deactivate own account", async ({ page }) => {
    const profilePage = new MyProfilePage(page);
    await profilePage.goto();

    await expect(page.getByRole("button", { name: /deactivate/i })).toBeHidden();
  });
});

test.describe("user--view-own-profile", () => {
  useActor(test, "user");

  test("View profile showing name, email, and assigned roles", async ({ page }) => {
    const profilePage = new MyProfilePage(page);
    await profilePage.goto();
    await expect(profilePage.heading).toBeVisible();
    await expect(profilePage.nameField).toBeVisible();
    await expect(profilePage.emailField).toBeVisible();
    await expect(profilePage.rolesField).toBeVisible();
  });

  // Asserts the signed-in user's own identity, so use a dedicated account — the
  // worker's shared account may be mutated by other tests.
  test("Profile reflects the currently authenticated user's data", async ({ browser, baseURL }) => {
    const owner = await createUser({ permissions: ACTOR_PERMISSIONS.user });
    const context = await browser.newContext({
      baseURL,
      storageState: { cookies: [], origins: [] },
    });
    const page = await context.newPage();
    await new LoginPage(page).login(owner.email, owner.password);
    const profilePage = new MyProfilePage(page);
    await profilePage.goto();
    const main = page.getByRole("main");
    await expect(main.getByText(owner.name)).toBeVisible();
    await expect(main.getByText(owner.email)).toBeVisible();
    await context.close();
  });
});

test.describe("user--update-own-profile", () => {
  useActor(test, "user");

  // Mutates the signed-in user's own profile, so use a dedicated account — it
  // must not corrupt the worker's shared account other tests reuse.
  test("Update name or email with valid values", async ({ browser, baseURL }) => {
    const owner = await createUser({ permissions: ACTOR_PERMISSIONS.user });
    const context = await browser.newContext({
      baseURL,
      storageState: { cookies: [], origins: [] },
    });
    const page = await context.newPage();
    await new LoginPage(page).login(owner.email, owner.password);

    const profilePage = new MyProfilePage(page);
    await profilePage.goto();
    await profilePage.editButton.click();

    const editForm = new MyProfileEditFormPage(page);
    const newName = `Updated Profile ${Date.now()}`;
    await editForm.nameInput.clear();
    await editForm.nameInput.fill(newName);
    await editForm.submitButton.click();

    await expect(page.getByRole("main").getByText(newName)).toBeVisible();
    await context.close();
  });

  test("Submission with invalid values is blocked by validation", async ({ page }) => {
    const profilePage = new MyProfilePage(page);
    await profilePage.goto();
    await profilePage.editButton.click();

    const editForm = new MyProfileEditFormPage(page);
    await editForm.nameInput.clear();
    await editForm.submitButton.click();

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