import type { Ref } from 'vue';

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

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

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

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

function isDefined<T>(value: null | T | undefined): value is T {
  return value !== null && value !== undefined;
}

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

  function normalizeMoney(value: number) {
    return Number(Number(value).toFixed(2));
  }

  function resolveSpecOptionExtraPrice(templateId: string, optionId: string) {
    const template = specTemplateOptions.value.find(
      (item) => item.id === templateId,
    );
    if (!template) return 0;
    const option = template.values.find((item) => item.id === optionId);
    if (!option) return 0;
    const extraPrice = Number(option.extraPrice || 0);
    return Number.isFinite(extraPrice) ? extraPrice : 0;
  }

  function resolveSkuAttrsExtraPrice(
    attrs: ProductDetailSkuRowState['attributes'],
  ) {
    return attrs.reduce(
      (sum, item) =>
        sum + resolveSpecOptionExtraPrice(item.templateId, item.optionId),
      0,
    );
  }

  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 formatOptionExtraPrice(extraPrice: number) {
    const normalized = normalizeMoney(extraPrice);
    const prefix = normalized >= 0 ? '+' : '-';
    return `${prefix}¥${Math.abs(normalized).toFixed(2)}`;
  }

  function getOptionDisplayText(templateId: string, optionId: string) {
    if (!optionId) return '-';
    const name = getOptionName(templateId, optionId);
    const extraPrice = resolveSpecOptionExtraPrice(templateId, optionId);
    return `${name} (${formatOptionExtraPrice(extraPrice)})`;
  }

  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((item): item is ProductSpecDto => isDefined(item))
      .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 || '',
          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;
      const totalExtraPrice = resolveSkuAttrsExtraPrice(attrs);
      const defaultPrice = normalizeMoney(
        Math.max(0, Number(form.price || 0) + totalExtraPrice),
      );
      const defaultOriginalPrice =
        form.originalPrice !== null &&
        form.originalPrice !== undefined &&
        form.originalPrice > 0
          ? normalizeMoney(
              Math.max(0, Number(form.originalPrice) + totalExtraPrice),
            )
          : null;
      return {
        id: cached?.id || '',
        skuCode: cached?.skuCode || '',
        price: cached?.price ?? defaultPrice,
        originalPrice: cached?.originalPrice ?? defaultOriginalPrice,
        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) {
    const current = form.skus[index];
    if (!current) return;

    form.skus[index] = {
      ...current,
      price: Number.isFinite(value) ? Math.max(0, value) : current.price,
    };
  }

  function setSkuOriginalPrice(index: number, value: null | number) {
    const current = form.skus[index];
    if (!current) return;

    form.skus[index] = {
      ...current,
      originalPrice:
        value !== null && value !== undefined && Number(value) > 0
          ? Number(value)
          : null,
    };
  }

  function setSkuStock(index: number, value: number) {
    const current = form.skus[index];
    if (!current) return;

    form.skus[index] = {
      ...current,
      stock: Math.max(0, Math.floor(Number(value || 0))),
    };
  }

  function setSkuEnabled(index: number, checked: boolean) {
    const current = form.skus[index];
    if (!current) return;

    form.skus[index] = {
      ...current,
      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,
    getOptionDisplayText,
    getOptionName,
    getSkuAttrOptionId,
    getTemplateName,
    setSkuEnabled,
    setSkuOriginalPrice,
    setSkuPrice,
    setSkuStock,
    toggleSpecTemplate,
  };
}
