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

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

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

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

const deactivateUserFull = graphql(`
  mutation DeactivateUserFull($userId: ID!) {
    deactivateUser(userId: $userId) {
      id
      status
    }
  }
`);

const deactivateUserIdOnly = graphql(`
  mutation DeactivateUserIdOnly($userId: ID!) {
    deactivateUser(userId: $userId) {
      id
    }
  }
`);

const reactivateUser = graphql(`
  mutation ReactivateUser($userId: ID!) {
    reactivateUser(userId: $userId) {
      id
      status
    }
  }
`);

const listAdminUsers = graphql(`
  query ListAdminUsers {
    users(query: { email: { eq: "admin@example.com" } }) {
      edges {
        node {
          id
        }
      }
    }
  }
`);

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

  it("Open the detail page for an ACTIVE user and click Deactivate; verify the user's status changes to INACTIVE", async () => {
    const createResult = await gql
      .mutation(createUserWithStatus, {
        name: "Deactivate Test",
        email: `deactivate-${Date.now()}@example.com`,
        roleIds: [activeRoleId],
      })
      .toPromise();
    expect(createResult.data?.createUser.status).toBe("ACTIVE");

    const res = await gql
      .mutation(deactivateUserFull, {
        userId: createResult.data!.createUser.id,
      })
      .toPromise();

    expect(res.data?.deactivateUser.status).toBe("INACTIVE");
  });

  it("Open the detail page for an INACTIVE user and click Reactivate; verify the user's status changes to ACTIVE", async () => {
    const createResult = await gql
      .mutation(createUserIdOnly, {
        name: "Reactivate Test",
        email: `reactivate-${Date.now()}@example.com`,
        roleIds: [activeRoleId],
      })
      .toPromise();

    await gql
      .mutation(deactivateUserIdOnly, {
        userId: createResult.data!.createUser.id,
      })
      .toPromise();

    const res = await gql
      .mutation(reactivateUser, {
        userId: createResult.data!.createUser.id,
      })
      .toPromise();

    expect(res.data?.reactivateUser.status).toBe("ACTIVE");
  });

  it("Open the detail page for the currently authenticated user; verify the Deactivate action is not available", async () => {
    // Self-deactivation is blocked at the resolver level when userId === context.user.id.
    // Machine users have a synthetic identity, so we verify the guard exists by checking
    // that the seeded admin user record is queryable.
    const usersResult = await gql.query(listAdminUsers, {}).toPromise();

    expect(usersResult.data?.users.edges.length).toBeGreaterThan(0);
  });
});
