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: "updateAttribute",
  operation: "mutation",
  input: {
    id: t.uuid().description("Attribute ID"),
    name: t.string({ optional: true }).description("Attribute name"),
    values: t
      .object(
        {
          id: t.uuid({ optional: true }).description("Value ID (omit for new values)"),
          label: t.string().description("Value label"),
        },
        { array: true, optional: true },
      )
      .description("Desired attribute values"),
  },
  body: async (context) => {
    const db = getDB("main-db");
    const result = await db.transaction().execute(async (trx) => {
      const ctx = createContext(context);

      if (context.input.name) {
        const cmdResult = await pmModules.commands.updateProductAttribute(
          trx,
          { id: context.input.id, name: context.input.name },
          ctx,
        );
        if (!cmdResult.ok) {
          switch (cmdResult.error.code) {
            case "PRODUCT_MANAGEMENT_ATTRIBUTE_NOT_FOUND":
              throw new Error(`Attribute not found: ${context.input.id}`);
            case "PRODUCT_MANAGEMENT_MISSING_REQUIRED_FIELD":
              throw new Error(`Missing required field: ${cmdResult.error.message}`);
            case "INSUFFICIENT_PERMISSION":
              throw cmdResult.error;
            default:
              throw cmdResult.error satisfies never;
          }
        }
      }

      const desiredValues = context.input.values;
      let currentValues: { id: string; label: string }[] | undefined;
      if (desiredValues != null) {
        currentValues = await trx
          .selectFrom("ProductAttributeValue")
          .select(["id", "label"])
          .where("attributeId", "=", context.input.id)
          .execute();

        const currentMap = new Map(currentValues.map((v) => [v.id, v.label]));
        const desiredIds = new Set(desiredValues.filter((v) => v.id).map((v) => v.id!));

        // Delete values not in desired list
        for (const current of currentValues) {
          if (desiredIds.has(current.id)) continue;
          const r = await pmModules.commands.deleteProductAttributeValue(
            trx,
            { id: current.id },
            ctx,
          );
          if (!r.ok) {
            switch (r.error.code) {
              case "PRODUCT_MANAGEMENT_VALUE_NOT_FOUND":
                break;
              case "PRODUCT_MANAGEMENT_ATTRIBUTE_NOT_FOUND":
                break;
              case "PRODUCT_MANAGEMENT_VALUE_IN_USE":
                throw new Error(`Value ${current.id} is in use and cannot be deleted`);
              case "INSUFFICIENT_PERMISSION":
                throw r.error;
              default:
                throw r.error satisfies never;
            }
          }
        }

        // Update existing values with changed labels
        for (const val of desiredValues) {
          if (!val.id) continue;
          const currentLabel = currentMap.get(val.id);
          if (currentLabel === val.label) continue;
          const r = await pmModules.commands.updateProductAttributeValue(
            trx,
            { id: val.id, label: val.label },
            ctx,
          );
          if (!r.ok) {
            switch (r.error.code) {
              case "PRODUCT_MANAGEMENT_VALUE_NOT_FOUND":
                throw new Error(`Value ${val.id} does not exist`);
              case "PRODUCT_MANAGEMENT_DUPLICATE_VALUE":
                throw new Error(`Duplicate value label: ${val.label}`);
              case "PRODUCT_MANAGEMENT_INVALID_LABEL":
                throw new Error(`Invalid label: ${val.label}`);
              case "INSUFFICIENT_PERMISSION":
                throw r.error;
              default:
                throw r.error satisfies never;
            }
          }
        }

        // Create new values
        for (const val of desiredValues) {
          if (val.id) continue;
          const r = await pmModules.commands.createProductAttributeValue(
            trx,
            { attributeId: context.input.id, label: val.label },
            ctx,
          );
          if (!r.ok) {
            switch (r.error.code) {
              case "PRODUCT_MANAGEMENT_ATTRIBUTE_NOT_FOUND":
                throw new Error(`Attribute ${context.input.id} does not exist`);
              case "PRODUCT_MANAGEMENT_DUPLICATE_VALUE":
                throw new Error(`Duplicate value label: ${val.label}`);
              case "PRODUCT_MANAGEMENT_INVALID_LABEL":
                throw new Error(`Invalid label: ${val.label}`);
              case "INSUFFICIENT_PERMISSION":
                throw r.error;
              default:
                throw r.error satisfies never;
            }
          }
        }
      }

      return { id: context.input.id };
    });

    return { id: result.id };
  },
  output: t
    .object({
      id: t.uuid().description("Attribute ID"),
    })
    .description("Updated attribute"),
});
