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

const createCategoryIdOnly = graphql(`
  mutation CreateCategoryForDelete($code: String!, $name: String!, $parentId: ID) {
    createCategory(code: $code, name: $name, parentId: $parentId) {
      id
    }
  }
`);

const deleteCategory = graphql(`
  mutation DeleteCategory($id: ID!) {
    deleteCategory(id: $id) {
      id
    }
  }
`);

const listUnits = graphql(`
  query ListUnitsForDelete {
    units {
      edges {
        node {
          id
        }
      }
    }
  }
`);

const createProductIdOnly = graphql(`
  mutation CreateProductForDeleteCat($code: String!, $name: String!, $unitId: ID!) {
    createProduct(code: $code, name: $name, unitId: $unitId) {
      id
    }
  }
`);

const updateProductCategories = graphql(`
  mutation AssignProductForDeleteCat($productId: ID!, $categoryIds: [ID!]!) {
    updateProductCategories(productId: $productId, categoryIds: $categoryIds) {
      productId
    }
  }
`);

describe("product-manager--delete-category", () => {
  const gql = createGraphQLClient(inject("url"), inject("token"));

  it("Given a leaf category with no children and no product assignments, the category is deleted successfully", async () => {
    const code = `DEL-LEAF-${Date.now()}`;
    const createResult = await gql
      .mutation(createCategoryIdOnly, { code, name: "Leaf to Delete" })
      .toPromise();
    const categoryId = createResult.data!.createCategory.id;

    const result = await gql.mutation(deleteCategory, { id: categoryId }).toPromise();

    expect(result.data?.deleteCategory.id).toBe(categoryId);
  });

  it("Given a category with at least one child category, deletion fails with a has children error", async () => {
    const ts = Date.now();
    const parentResult = await gql
      .mutation(createCategoryIdOnly, { code: `DEL-P-${ts}`, name: "Parent" })
      .toPromise();
    const parentId = parentResult.data!.createCategory.id;

    await gql
      .mutation(createCategoryIdOnly, { code: `DEL-C-${ts}`, name: "Child", parentId })
      .toPromise();

    await expect(gql.mutation(deleteCategory, { id: parentId }).toPromise()).rejects.toThrow();
  });

  it("Given a category with at least one product assignment, deletion fails with a has products error", async () => {
    const ts = Date.now();
    const catResult = await gql
      .mutation(createCategoryIdOnly, { code: `DEL-PROD-${ts}`, name: "Category With Product" })
      .toPromise();
    const categoryId = catResult.data!.createCategory.id;

    const unitsResult = await gql.query(listUnits, {}).toPromise();
    const uomId = unitsResult.data!.units.edges[0].node.id;

    const productResult = await gql
      .mutation(createProductIdOnly, { code: `PROD-DEL-${ts}`, name: "Product", unitId: uomId })
      .toPromise();
    const productId = productResult.data!.createProduct.id;

    await gql
      .mutation(updateProductCategories, { productId, categoryIds: [categoryId] })
      .toPromise();

    await expect(gql.mutation(deleteCategory, { id: categoryId }).toPromise()).rejects.toThrow();
  });
});
