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

const listRoles = graphql(`
  query ListRoles {
    roles {
      edges {
        node {
          id
        }
      }
    }
  }
`);

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

const updateUserProfileName = graphql(`
  mutation UpdateUserProfileName($userId: String!, $name: String, $email: String) {
    updateUserProfile(userId: $userId, name: $name, email: $email) {
      id
      name
    }
  }
`);

const updateUserProfileEmail = graphql(`
  mutation UpdateUserProfileEmail($userId: String!, $name: String, $email: String) {
    updateUserProfile(userId: $userId, name: $name, email: $email) {
      id
      email
    }
  }
`);

const updateUserProfileIdOnly = graphql(`
  mutation UpdateUserProfileIdOnly($userId: String!, $name: String, $email: String) {
    updateUserProfile(userId: $userId, name: $name, email: $email) {
      id
    }
  }
`);

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

  it("Change a user's name and submit; verify the updated name is reflected on the detail page", async () => {
    const rolesResult = await gql.query(listRoles, {}).toPromise();
    const roleId = rolesResult.data?.roles.edges[0].node.id;
    const email = `update-name-${Date.now()}@example.com`;

    const createResult = await gql
      .mutation(createUserIdOnly, {
        name: "Before Update",
        email,
        roleIds: [roleId!],
      })
      .toPromise();

    const res = await gql
      .mutation(updateUserProfileName, {
        userId: createResult.data!.createUser.id,
        name: "After Update",
        email,
      })
      .toPromise();

    expect(res.data?.updateUserProfile.name).toBe("After Update");
  });

  it("Change a user's email to a valid unique address and submit; verify the updated email is shown", async () => {
    const rolesResult = await gql.query(listRoles, {}).toPromise();
    const roleId = rolesResult.data?.roles.edges[0].node.id;
    const ts = Date.now();

    const createResult = await gql
      .mutation(createUserIdOnly, {
        name: "Email Update User",
        email: `old-email-${ts}@example.com`,
        roleIds: [roleId!],
      })
      .toPromise();

    const newEmail = `new-email-${ts}@example.com`;
    const res = await gql
      .mutation(updateUserProfileEmail, {
        userId: createResult.data!.createUser.id,
        name: "Email Update User",
        email: newEmail,
      })
      .toPromise();

    expect(res.data?.updateUserProfile.email).toBe(newEmail);
  });

  it("Change a user's email to one already assigned to another user; verify an error is shown and no change is saved", async () => {
    const rolesResult = await gql.query(listRoles, {}).toPromise();
    const roleId = rolesResult.data?.roles.edges[0].node.id;
    const ts = Date.now();

    await gql
      .mutation(createUserIdOnly, {
        name: "User A",
        email: `dup-a-${ts}@example.com`,
        roleIds: [roleId!],
      })
      .toPromise();

    const createB = await gql
      .mutation(createUserIdOnly, {
        name: "User B",
        email: `dup-b-${ts}@example.com`,
        roleIds: [roleId!],
      })
      .toPromise();

    await expect(
      gql
        .mutation(updateUserProfileIdOnly, {
          userId: createB.data!.createUser.id,
          name: "User B",
          email: `dup-a-${ts}@example.com`,
        })
        .toPromise(),
    ).rejects.toThrow();
  });

  it("Clear the name field and submit; verify a validation error is shown", async () => {
    const rolesResult = await gql.query(listRoles, {}).toPromise();
    const roleId = rolesResult.data?.roles.edges[0].node.id;
    const email = `clear-name-${Date.now()}@example.com`;

    const createResult = await gql
      .mutation(createUserIdOnly, {
        name: "Clear Name User",
        email,
        roleIds: [roleId!],
      })
      .toPromise();

    await expect(
      gql
        .mutation(updateUserProfileName, {
          userId: createResult.data!.createUser.id,
          name: "",
          email,
        })
        .toPromise(),
    ).rejects.toThrow();
  });
});
