import type { DrizzleClient } from '@/server/db/client';
import { setInventory, toInventoryTx } from '@/server/stock/inventory-platform.js';
import { dealSkus, dealVariantAxes, dealVariantOptions, deals } from '@/server/db/schema';
import { dealTypeCaps, type DealType } from '@/lib/deal-types';
import { buildDefaultSkuRow } from '@/server/domain/variants/default-sku';
import { refreshDealCache } from '@/server/domain/variants/cache';
import { hashOptionIds } from '@/server/domain/variants/hash';
import { validateDealHasSkus } from './validate-has-skus';

export interface CreateDealInput {
  dealRow: typeof deals.$inferInsert;
  mode: 'single' | 'variants';
  single?: { originalPrice: string; discountPercent: number; discountedPrice: string; quantityTotal: number };
  variants?: {
    axes: { axisOrder: number; kind: 'SIZE' | 'COLOR' | 'TIMESLOT' | 'CUSTOM'; nameHe: string; nameEn: string;
      options: { optionOrder: number; valueCode: string; labelHe: string; labelEn: string;
        slotStart?: Date | null; slotEnd?: Date | null; swatchHex?: string | null }[] }[];
    skus: { optionValueCodes: string[]; originalPrice: string; discountPercent: number;
      discountedPrice: string; quantityTotal: number }[];
  };
}

export async function createDealWithSkus(tx: DrizzleClient, input: CreateDealInput): Promise<{ dealId: string }> {
  // GROUP deals do not support variant axes/SKUs — they use a single default SKU only.
  if (!dealTypeCaps(input.dealRow.dealType as DealType).allowsVariants && input.mode === 'variants') {
    throw new Error('GROUP_NO_VARIANTS');
  }

  const [deal] = await tx.insert(deals).values(input.dealRow).returning({ id: deals.id });
  if (!deal) throw new Error('DEAL_INSERT_FAILED');

  if (input.mode === 'single') {
    if (!input.single) throw new Error('SINGLE_MODE_REQUIRES_PRICE_BLOCK');
    const [newSku] = await tx
      .insert(dealSkus)
      .values(buildDefaultSkuRow({ dealId: deal.id, ...input.single }))
      .returning({ id: dealSkus.id });
    if (newSku) {
      await setInventory(toInventoryTx(tx), {
        skuId: newSku.id,
        vendorId: input.dealRow.vendorId ?? null,
        quantityTotal: input.single.quantityTotal,
      });
    }
  } else {
    if (!input.variants) throw new Error('VARIANTS_MODE_REQUIRES_PAYLOAD');
    const axisIdsByOrder = new Map<number, string>();
    const optionIdsByAxisOrderAndCode = new Map<string, string>();
    for (const ax of input.variants.axes) {
      const [a] = await tx.insert(dealVariantAxes).values({
        dealId: deal.id, axisOrder: ax.axisOrder, kind: ax.kind, nameHe: ax.nameHe, nameEn: ax.nameEn,
      }).returning({ id: dealVariantAxes.id });
      if (!a) throw new Error('AXIS_INSERT_FAILED');
      axisIdsByOrder.set(ax.axisOrder, a.id);
      if (ax.options.length === 0) throw new Error('AXIS_NO_OPTIONS');
      for (const opt of ax.options) {
        const [o] = await tx.insert(dealVariantOptions).values({
          axisId: a.id, optionOrder: opt.optionOrder, valueCode: opt.valueCode,
          labelHe: opt.labelHe, labelEn: opt.labelEn,
          slotStart: opt.slotStart ?? null, slotEnd: opt.slotEnd ?? null, swatchHex: opt.swatchHex ?? null,
        }).returning({ id: dealVariantOptions.id });
        if (!o) throw new Error('OPTION_INSERT_FAILED');
        optionIdsByAxisOrderAndCode.set(`${ax.axisOrder}|${opt.valueCode}`, o.id);
      }
    }
    if (input.variants.skus.length === 0) throw new Error('VARIANTS_EMPTY');
    for (const skuSpec of input.variants.skus) {
      const optionIds = skuSpec.optionValueCodes.map((code, idx) => {
        const id = optionIdsByAxisOrderAndCode.get(`${idx}|${code}`);
        if (!id) throw new Error(`OPTION_CODE_UNKNOWN:${idx}|${code}`);
        return id;
      });
      const [variantSku] = await tx
        .insert(dealSkus)
        .values({
          dealId: deal.id,
          optionIds,
          optionIdsHash: hashOptionIds(optionIds),
          originalPrice: skuSpec.originalPrice,
          discountPercent: skuSpec.discountPercent,
          discountedPrice: skuSpec.discountedPrice,
          quantityTotal: skuSpec.quantityTotal,
        })
        .returning({ id: dealSkus.id });
      if (variantSku) {
        await setInventory(toInventoryTx(tx), {
          skuId: variantSku.id,
          vendorId: input.dealRow.vendorId ?? null,
          quantityTotal: skuSpec.quantityTotal,
        });
      }
    }
  }

  await refreshDealCache(tx, deal.id);
  await validateDealHasSkus(tx, deal.id);
  return { dealId: deal.id };
}
