import type { Ref } from 'vue';

import type { ProductSpecDto } from '#/api/product';

import type {
  ProductDetailFormState,
  ProductDetailSkuBatchState,
  ProductDetailSkuRowState,
} from '../../types';

import {
  buildLocalSkuCode,
  buildSkuCombinations,
  buildSkuKey,
} from './helpers';

interface CreateProductDetailSkuActionsOptions {
  form: ProductDetailFormState;
  skuBatch: ProductDetailSkuBatchState;
  specTemplateOptions: Ref<ProductSpecDto[]>;
}

export function createProductDetailSkuActions(
  options: CreateProductDetailSkuActionsOptions,
) {
  const { form, skuBatch, specTemplateOptions } = options;

  function getTemplateName(templateId: string) {
    return (
      specTemplateOptions.value.find((item) => item.id === templateId)?.name ||
      templateId
    );
  }

  function getOptionName(templateId: string, optionId: string) {
    const template = specTemplateOptions.value.find(
      (item) => item.id === templateId,
    );
    if (!template) return optionId;
    return (
      template.values.find((item) => item.id === optionId)?.name || optionId
    );
  }

  function getSkuAttrOptionId(row: ProductDetailSkuRowState, templateId: string) {
    return row.attributes.find((item) => item.templateId === templateId)
      ?.optionId;
  }

  function buildSkuRows() {
    const selectedTemplates = form.specTemplateIds
      .map((id) => specTemplateOptions.value.find((item) => item.id === id))
      .filter(Boolean)
      .map((item) => ({
        id: item.id,
        name: item.name,
        options: [...(item.values || [])]
          .toSorted((a, b) => a.sort - b.sort)
          .map((value) => ({
            id: value.id,
            name: value.name,
          })),
      }))
      .filter((item) => item.options.length > 0);

    const previousMap = new Map(
      form.skus.map((item) => [buildSkuKey(item.attributes), item]),
    );

    const combos = buildSkuCombinations(selectedTemplates);
    if (combos.length === 0) {
      const fallback = previousMap.get('default');
      form.skus = [
        {
          id: fallback?.id || '',
          skuCode: fallback?.skuCode || buildLocalSkuCode(1),
          price: fallback?.price ?? Number(form.price || 0),
          originalPrice:
            fallback?.originalPrice ??
            (form.originalPrice && form.originalPrice > 0
              ? form.originalPrice
              : null),
          stock:
            fallback?.stock ?? Math.max(0, Math.floor(Number(form.stock || 0))),
          isEnabled: fallback?.isEnabled ?? true,
          sortOrder: 1,
          attributes: [],
        },
      ];
      return;
    }

    form.skus = combos.map((attrs, index) => {
      const key = buildSkuKey(attrs);
      const cached = previousMap.get(key);
      const skuIndex = index + 1;
      return {
        id: cached?.id || '',
        skuCode: cached?.skuCode || buildLocalSkuCode(skuIndex),
        price: cached?.price ?? Number(form.price || 0),
        originalPrice:
          cached?.originalPrice ??
          (form.originalPrice && form.originalPrice > 0
            ? form.originalPrice
            : null),
        stock:
          cached?.stock ?? Math.max(0, Math.floor(Number(form.stock || 0))),
        isEnabled: cached?.isEnabled ?? true,
        sortOrder: skuIndex,
        attributes: attrs,
      };
    });
  }

  function toggleSpecTemplate(templateId: string) {
    const selected = new Set(form.specTemplateIds);
    if (selected.has(templateId)) {
      selected.delete(templateId);
    } else {
      selected.add(templateId);
    }
    form.specTemplateIds = [...selected];
    buildSkuRows();
  }

  function setSkuPrice(index: number, value: number) {
    if (index < 0 || index >= form.skus.length) return;
    form.skus[index] = {
      ...form.skus[index],
      price: Number.isFinite(value)
        ? Math.max(0, value)
        : form.skus[index].price,
    };
  }

  function setSkuOriginalPrice(index: number, value: null | number) {
    if (index < 0 || index >= form.skus.length) return;
    form.skus[index] = {
      ...form.skus[index],
      originalPrice:
        value !== null && value !== undefined && Number(value) > 0
          ? Number(value)
          : null,
    };
  }

  function setSkuStock(index: number, value: number) {
    if (index < 0 || index >= form.skus.length) return;
    form.skus[index] = {
      ...form.skus[index],
      stock: Math.max(0, Math.floor(Number(value || 0))),
    };
  }

  function setSkuEnabled(index: number, checked: boolean) {
    if (index < 0 || index >= form.skus.length) return;
    form.skus[index] = {
      ...form.skus[index],
      isEnabled: checked,
    };
  }

  function applySkuBatchPrice() {
    if (skuBatch.price === null || skuBatch.price === undefined) return;
    const price = Math.max(0, Number(skuBatch.price));
    form.skus = form.skus.map((item) => ({
      ...item,
      price,
    }));
  }

  function applySkuBatchStock() {
    if (skuBatch.stock === null || skuBatch.stock === undefined) return;
    const stock = Math.max(0, Math.floor(Number(skuBatch.stock)));
    form.skus = form.skus.map((item) => ({
      ...item,
      stock,
    }));
  }

  return {
    applySkuBatchPrice,
    applySkuBatchStock,
    buildSkuRows,
    getOptionName,
    getSkuAttrOptionId,
    getTemplateName,
    setSkuEnabled,
    setSkuOriginalPrice,
    setSkuPrice,
    setSkuStock,
    toggleSpecTemplate,
  };
}
