import { beforeAll, describe, expect, inject, it } from "vitest";
import { createGraphQLClient, graphql } from "@/tests/utils/graphql-client";

const createActiveRole = graphql(`
  mutation CreateActiveRoleForCreateAccount($name: String!, $permissions: [String!]!) {
    createRole(name: $name, permissions: $permissions) {
      id
    }
  }
`);

const createUserFull = graphql(`
  mutation CreateUserFull($name: String!, $email: String!, $roleIds: [ID!]) {
    createUser(name: $name, email: $email, roleIds: $roleIds) {
      id
      name
      email
      status
    }
  }
`);

const createUserIdOnly = graphql(`
  mutation CreateUserIdOnly($name: String!, $email: String!, $roleIds: [ID!]) {
    createUser(name: $name, email: $email, roleIds: $roleIds) {
      id
    }
  }
`);

describe("user--create-user-account", () => {
  const gql = createGraphQLClient(inject("url"), inject("token"));

  // Create our own active role so this file does not depend on seeded roles.
  // Other tests deactivate roles in parallel, so reusing one from the list is unsafe.
  let activeRoleId: string;
  beforeAll(async () => {
    const res = await gql
      .mutation(createActiveRole, { name: `create-acct-active-${Date.now()}`, permissions: [] })
      .toPromise();
    activeRoleId = res.data!.createRole.id;
  });

  it("Submit the form with valid name, email, and one or more roles; verify the user appears in the list with ACTIVE status", async () => {
    const email = `create-test-${Date.now()}@example.com`;
    const res = await gql
      .mutation(createUserFull, { name: "Test User", email, roleIds: [activeRoleId] })
      .toPromise();

    expect(res.data?.createUser.name).toBe("Test User");
    expect(res.data?.createUser.email).toBe(email);
    expect(res.data?.createUser.status).toBe("ACTIVE");
  });

  it("Submit the form with valid name and email but no roles; verify the user is created with ACTIVE status", async () => {
    const email = `no-role-test-${Date.now()}@example.com`;
    const res = await gql
      .mutation(createUserFull, { name: "No Role User", email, roleIds: [] })
      .toPromise();

    expect(res.data?.createUser.name).toBe("No Role User");
    expect(res.data?.createUser.email).toBe(email);
    expect(res.data?.createUser.status).toBe("ACTIVE");
  });

  it("Submit the form with an email address already assigned to another user; verify an error is shown and no user is created", async () => {
    const email = `dup-test-${Date.now()}@example.com`;
    await gql
      .mutation(createUserIdOnly, {
        name: "First User",
        email,
        roleIds: [activeRoleId],
      })
      .toPromise();

    await expect(
      gql
        .mutation(createUserIdOnly, {
          name: "Duplicate User",
          email,
          roleIds: [activeRoleId],
        })
        .toPromise(),
    ).rejects.toThrow();
  });

  it("Submit the form with the name field empty; verify a validation error is shown and submission is blocked", async () => {
    await expect(
      gql
        .mutation(createUserIdOnly, {
          name: "",
          email: `empty-name-${Date.now()}@example.com`,
        })
        .toPromise(),
    ).rejects.toThrow();
  });
});
