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

interface AttributeValue {
  id: string;
  label: string;
}
interface VariantItem {
  id: string;
  sku: string;
}

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

const createAttribute = graphql(`
  mutation ViewerCreateAttributeForVariantList(
    $code: String!
    $name: String!
    $valueLabels: [String!]
  ) {
    createAttribute(code: $code, name: $name, valueLabels: $valueLabels) {
      id
    }
  }
`);

const getAttributeValues = graphql(`
  query ViewerGetAttributeValuesForVariantList($id: ID!) {
    productAttribute(id: $id) {
      id
      productAttributeValues {
        edges {
          node {
            id
            label
          }
        }
      }
    }
  }
`);

const createProduct = graphql(`
  mutation ViewerCreateProductForVariantList(
    $code: String!
    $name: String!
    $unitId: ID!
    $attributes: [CreateProductInputAttributes!]
  ) {
    createProduct(code: $code, name: $name, unitId: $unitId, attributes: $attributes) {
      id
    }
  }
`);

const updateProductAttributes = graphql(`
  mutation ViewerUpdateProductAttributesForVariantList(
    $productId: ID!
    $attributes: [UpdateProductAttributesInputAttributes!]!
  ) {
    updateProductAttributes(productId: $productId, attributes: $attributes) {
      productId
    }
  }
`);

const activateProduct = graphql(`
  mutation ViewerActivateProductForVariantList($id: ID!) {
    activateProduct(id: $id) {
      id
      status
    }
  }
`);

const generateVariants = graphql(`
  mutation ViewerGenerateVariantsForList($productId: ID!) {
    generateVariants(productId: $productId) {
      generatedCount
    }
  }
`);

const getProduct = graphql(`
  query ViewerGetProductForVariantList($id: ID!) {
    product(id: $id) {
      id
      productVariants {
        edges {
          node {
            id
            item {
              id
              sku
            }
          }
        }
      }
    }
  }
`);

describe("viewer--browse-variant-list", () => {
  const gql = createGraphQLClient(inject("url"), inject("token"));

  it("Given variants have been generated for a product, when the variant list is opened, then each Item is shown with its SKU and attribute value combination.", async () => {
    const ts = Date.now();
    const unitsResult = await gql.query(listUnits, {}).toPromise();
    const unitId = unitsResult.data!.units.edges[0].node.id;

    const attrRes = await gql
      .mutation(createAttribute, {
        code: `VW-COLOR-${ts}`,
        name: "Color",
        valueLabels: ["Red", "Blue"],
      })
      .toPromise();
    const attrId = attrRes.data!.createAttribute.id;

    const attrValues = await gql.query(getAttributeValues, { id: attrId }).toPromise();
    const values = attrValues.data!.productAttribute!.productAttributeValues.edges.map(
      (e) => e.node,
    ) as AttributeValue[];

    const productRes = await gql
      .mutation(createProduct, {
        code: `VW-PROD-${ts}`,
        name: "Viewer Variant Product",
        unitId,
        attributes: values.map((v: AttributeValue) => ({
          attributeId: attrId,
          valueId: v.id,
        })) as never,
      })
      .toPromise();
    const productId = productRes.data!.createProduct.id;

    await gql
      .mutation(updateProductAttributes, {
        productId,
        attributes: values.map((v: AttributeValue) => ({
          attributeId: attrId,
          valueId: v.id,
        })) as never,
      })
      .toPromise();

    await gql.mutation(activateProduct, { id: productId }).toPromise();
    await gql.mutation(generateVariants, { productId }).toPromise();

    const res = await gql.query(getProduct, { id: productId }).toPromise();

    const variants = res.data!.product!.productVariants.edges.map((e) => e.node);
    expect(variants.length).toBeGreaterThan(0);
    for (const variant of variants) {
      const item = variant.item as VariantItem;
      expect(item.sku).toBeDefined();
      expect(item.id).toBeDefined();
    }
  });

  it("Given no variants exist for a product, when the variant list is opened, then an empty state is displayed.", async () => {
    const ts = Date.now();
    const unitsResult = await gql.query(listUnits, {}).toPromise();
    const unitId = unitsResult.data!.units.edges[0].node.id;

    const productRes = await gql
      .mutation(createProduct, {
        code: `VW-NOVAR-${ts}`,
        name: "Viewer No Variant Product",
        unitId,
      })
      .toPromise();
    const productId = productRes.data!.createProduct.id;

    const res = await gql.query(getProduct, { id: productId }).toPromise();
    const noVariants = res.data!.product!.productVariants.edges;

    expect(noVariants).toHaveLength(0);
  });
});
