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

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

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

const updateUserRoles = graphql(`
  mutation ($userId: ID!, $roleIds: [ID!]!) {
    updateUserRoles(userId: $userId, roleIds: $roleIds) {
      userId
    }
  }
`);

const listUserRoles = graphql(`
  query ListUserRoles($userId: ID!) {
    userRoles(query: { userId: { eq: $userId } }) {
      edges {
        node {
          roleId
        }
      }
    }
  }
`);

describe("user--remove-role-from-user", () => {
  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: `remove-active-${Date.now()}`, permissions: [] })
      .toPromise();
    activeRoleId = res.data!.createRole.id;
  });

  it("Select an assigned role on a user, click Remove, and confirm; verify the role no longer appears in the user's role list", async () => {
    const createResult = await gql
      .mutation(createUser, {
        name: "Remove Role User",
        email: `remove-role-${Date.now()}@example.com`,
        roleIds: [activeRoleId],
      })
      .toPromise();
    const userId = createResult.data!.createUser.id;

    // Remove the role by passing empty array
    await gql.mutation(updateUserRoles, { userId, roleIds: [] }).toPromise();

    const userRolesResult = await gql.query(listUserRoles, { userId }).toPromise();
    const assignedRoleIds = userRolesResult.data?.userRoles.edges.map(
      (edge: { node: { roleId: string } }) => edge.node.roleId,
    );
    expect(assignedRoleIds).not.toContain(activeRoleId);
  });

  it("Select an assigned role on a user, click Remove, and cancel; verify the role still appears in the user's role list", async () => {
    // "Cancel" is a frontend-only action. Verify that without calling updateUserRoles, the role remains.
    const createResult = await gql
      .mutation(createUser, {
        name: "Cancel Remove User",
        email: `cancel-remove-${Date.now()}@example.com`,
        roleIds: [activeRoleId],
      })
      .toPromise();
    const userId = createResult.data!.createUser.id;

    // Do NOT call updateUserRoles — simulate cancel
    const userRolesResult = await gql.query(listUserRoles, { userId }).toPromise();
    const assignedRoleIds = userRolesResult.data?.userRoles.edges.map(
      (edge: { node: { roleId: string } }) => edge.node.roleId,
    );
    expect(assignedRoleIds).toContain(activeRoleId);
  });
});
