import { createContext } from "@tailor-platform/erp-kit/app";
import { createResolver, t } from "@tailor-platform/sdk";
import { getDB } from "@/generated/kysely-tailordb";
import { pmModules } from "@/modules";

export default createResolver({
  name: "createProduct",
  operation: "mutation",
  input: {
    code: t.string().description("Product code"),
    name: t.string().description("Product name"),
    description: t.string({ optional: true }).description("Product description"),
    unitId: t.uuid().description("Unit of measure ID"),
    categoryIds: t.uuid({ array: true, optional: true }).description("Category IDs to assign"),
    attributes: t
      .object(
        {
          attributeId: t.uuid().description("Attribute ID"),
          valueId: t.uuid().description("Value ID"),
        },
        { array: true, optional: true },
      )
      .description("Attribute value assignments"),
  },
  body: async (context) => {
    const db = getDB("main-db");
    const result = await db.transaction().execute(async (trx) => {
      const cmdResult = await pmModules.commands.createProduct(
        trx,
        {
          code: context.input.code,
          name: context.input.name,
          description: context.input.description ?? undefined,
          unitId: context.input.unitId,
        },
        createContext(context),
      );
      if (!cmdResult.ok) {
        switch (cmdResult.error.code) {
          case "PRODUCT_MANAGEMENT_DUPLICATE_CODE":
            throw new Error(`A product with code ${context.input.code} already exists`);
          case "PRODUCT_MANAGEMENT_MISSING_REQUIRED_FIELD":
            throw new Error(`Missing required field: ${cmdResult.error.message}`);
          case "PRODUCT_MANAGEMENT_INVALID_UOM":
            throw new Error(`Invalid unit of measure: ${context.input.unitId}`);
          case "INSUFFICIENT_PERMISSION":
            throw cmdResult.error;
          default:
            throw cmdResult.error satisfies never;
        }
      }
      for (const categoryId of context.input.categoryIds ?? []) {
        const assignResult = await pmModules.commands.assignProductToCategory(
          trx,
          {
            productId: cmdResult.value.product.id,
            categoryId,
          },
          createContext(context),
        );
        if (!assignResult.ok) {
          switch (assignResult.error.code) {
            case "PRODUCT_MANAGEMENT_PRODUCT_NOT_FOUND":
              throw new Error(`Product not found`);
            case "PRODUCT_MANAGEMENT_CATEGORY_NOT_FOUND":
              throw new Error(`Category ${categoryId} does not exist`);
            case "INSUFFICIENT_PERMISSION":
              throw assignResult.error;
            default:
              throw assignResult.error satisfies never;
          }
        }
      }

      for (const attr of context.input.attributes ?? []) {
        const attrResult = await pmModules.commands.assignAttributeValueToProduct(
          trx,
          {
            productId: cmdResult.value.product.id,
            attributeId: attr.attributeId,
            valueId: attr.valueId,
          },
          createContext(context),
        );
        if (!attrResult.ok) {
          switch (attrResult.error.code) {
            case "PRODUCT_MANAGEMENT_PRODUCT_NOT_FOUND":
              throw new Error(`Product not found`);
            case "PRODUCT_MANAGEMENT_ATTRIBUTE_NOT_FOUND":
              throw new Error(`Attribute ${attr.attributeId} does not exist`);
            case "PRODUCT_MANAGEMENT_PRODUCT_ARCHIVED":
              throw new Error(`Product is archived`);
            case "PRODUCT_MANAGEMENT_AXIS_STRUCTURE_LOCKED":
              throw new Error("Axis structure is locked");
            case "PRODUCT_MANAGEMENT_INVALID_VALUE":
              throw new Error(`Invalid attribute value: ${attrResult.error.message}`);
            case "INSUFFICIENT_PERMISSION":
              throw attrResult.error;
            default:
              throw attrResult.error satisfies never;
          }
        }
      }

      return {
        id: cmdResult.value.product.id,
        code: cmdResult.value.product.code,
        name: cmdResult.value.product.name,
        status: cmdResult.value.product.status,
      };
    });

    return result;
  },
  output: t
    .object({
      id: t.uuid().description("Product ID"),
      code: t.string().description("Product code"),
      name: t.string().description("Product name"),
      status: t.string().description("Product status"),
    })
    .description("Created product"),
});
