import type { Ref } from 'vue';
import type { Router } from 'vue-router';

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

import type {
  ProductAddonGroupDto,
  ProductDetailDto,
  ProductLabelDto,
  ProductSpecDto,
  ProductStatus,
} from '#/api/product';

import { message } from 'ant-design-vue';

import { uploadTenantFileApi } from '#/api/files';
import {
  createProductSkuSaveJobApi,
  deleteProductApi,
  getProductAddonGroupListApi,
  getProductCategoryListApi,
  getProductDetailApi,
  getProductLabelListApi,
  getProductSkuSaveJobApi,
  getProductSpecListApi,
  saveProductAsyncApi,
} from '#/api/product';

import { DEFAULT_PRODUCT_DETAIL_FORM } from './constants';
import {
  dedupeTextList,
  normalizeComboGroups,
  normalizeSkuRows,
} from './helpers';

const MAX_PRODUCT_IMAGE_COUNT = 5;
const ALLOWED_PRODUCT_IMAGE_MIME_SET = new Set([
  'image/jpeg',
  'image/png',
  'image/webp',
]);
const ALLOWED_PRODUCT_IMAGE_EXT = ['.jpg', '.jpeg', '.png', '.webp'];
const ASYNC_SKU_POLL_INTERVAL_MS = 1000;
const ASYNC_SKU_POLL_MAX_ATTEMPTS = 180;

interface CreateProductDetailDataActionsOptions {
  addonGroupOptions: Ref<ProductAddonGroupDto[]>;
  buildSkuRows: () => void;
  categoryOptions: Ref<ProductDetailCategoryOption[]>;
  detail: Ref<null | ProductDetailDto>;
  form: ProductDetailFormState;
  isLoading: Ref<boolean>;
  isSubmitting: Ref<boolean>;
  isUploadingImage: Ref<boolean>;
  labelOptions: Ref<ProductLabelDto[]>;
  productId: Ref<string>;
  router: Router;
  specTemplateOptions: Ref<ProductSpecDto[]>;
  storeId: Ref<string>;
}

export function createProductDetailDataActions(
  options: CreateProductDetailDataActionsOptions,
) {
  const {
    addonGroupOptions,
    buildSkuRows,
    categoryOptions,
    detail,
    form,
    isLoading,
    isSubmitting,
    isUploadingImage,
    labelOptions,
    productId,
    router,
    specTemplateOptions,
    storeId,
  } = options;
  let activeSkuSaveJobId = '';

  function resetForm() {
    Object.assign(form, {
      ...DEFAULT_PRODUCT_DETAIL_FORM,
      imageUrls: [],
      specTemplateIds: [],
      addonGroupIds: [],
      labelIds: [],
      skus: [],
      comboGroups: [],
    });
  }

  function patchForm(data: ProductDetailDto) {
    form.id = data.id;
    form.name = data.name;
    form.subtitle = data.subtitle;
    form.categoryId = data.categoryId;
    form.kind = data.kind;
    form.description = data.description;
    form.sortWeight = Math.max(0, Number(data.sortWeight || 0));

    form.imageUrls = dedupeTextList([
      ...(data.imageUrls || []),
      data.imageUrl,
    ]).slice(0, MAX_PRODUCT_IMAGE_COUNT);

    form.price = Number(data.price || 0);
    form.originalPrice =
      data.originalPrice !== null && data.originalPrice !== undefined
        ? Number(data.originalPrice)
        : null;
    form.stock = Math.max(0, Math.floor(Number(data.stock || 0)));
    form.warningStock =
      data.warningStock !== null && data.warningStock !== undefined
        ? Math.max(0, Math.floor(Number(data.warningStock)))
        : null;
    form.packingFee =
      data.packingFee !== null && data.packingFee !== undefined
        ? Number(data.packingFee)
        : null;

    form.specTemplateIds = dedupeTextList(data.specTemplateIds || []);
    form.addonGroupIds = dedupeTextList(data.addonGroupIds || []);
    form.labelIds = dedupeTextList(data.labelIds || []);

    form.skus = normalizeSkuRows(data.skus || []);
    form.comboGroups = normalizeComboGroups(data.comboGroups || []);

    form.status = data.status;
    if (data.status === 'on_sale') {
      form.shelfMode = 'now';
    } else if (data.timedOnShelfAt) {
      form.shelfMode = 'scheduled';
    } else {
      form.shelfMode = 'draft';
    }
    form.timedOnShelfAt = data.timedOnShelfAt || '';
  }

  function clearPageData() {
    detail.value = null;
    resetForm();
    categoryOptions.value = [];
    specTemplateOptions.value = [];
    addonGroupOptions.value = [];
    labelOptions.value = [];
  }

  function toggleAddonGroup(groupId: string) {
    const selected = new Set(form.addonGroupIds);
    if (selected.has(groupId)) {
      selected.delete(groupId);
    } else {
      selected.add(groupId);
    }
    form.addonGroupIds = [...selected];
  }

  function toggleLabel(labelId: string) {
    const selected = new Set(form.labelIds);
    if (selected.has(labelId)) {
      selected.delete(labelId);
    } else {
      selected.add(labelId);
    }
    form.labelIds = [...selected];
  }

  function isAllowedProductImageFile(file: File) {
    const mimeType = String(file.type || '')
      .trim()
      .toLowerCase();
    if (mimeType && ALLOWED_PRODUCT_IMAGE_MIME_SET.has(mimeType)) {
      return true;
    }

    const lowerName = String(file.name || '')
      .trim()
      .toLowerCase();
    return ALLOWED_PRODUCT_IMAGE_EXT.some((ext) => lowerName.endsWith(ext));
  }

  async function uploadImages(files: File[]) {
    if (files.length === 0) return;

    if (form.imageUrls.length >= MAX_PRODUCT_IMAGE_COUNT) {
      message.warning(`最多上传 ${MAX_PRODUCT_IMAGE_COUNT} 张图片`);
      return;
    }

    const invalidFiles = files.filter(
      (file) => !isAllowedProductImageFile(file),
    );
    if (invalidFiles.length > 0) {
      message.warning('仅支持 JPG/PNG/WEBP 格式');
    }

    const validFiles = files.filter((file) => isAllowedProductImageFile(file));
    if (validFiles.length === 0) return;

    const remainCount = MAX_PRODUCT_IMAGE_COUNT - form.imageUrls.length;
    let uploadQueue = validFiles;
    if (validFiles.length > remainCount) {
      uploadQueue = validFiles.slice(0, remainCount);
      message.warning(
        `最多上传 ${MAX_PRODUCT_IMAGE_COUNT} 张图片，本次仅上传前 ${remainCount} 张`,
      );
    }

    let successCount = 0;
    let failedCount = 0;

    isUploadingImage.value = true;
    try {
      for (const file of uploadQueue) {
        try {
          const uploaded = await uploadTenantFileApi(file, 'dish_image');
          const url = String(uploaded.url || '').trim();
          if (!url) {
            failedCount += 1;
            continue;
          }
          form.imageUrls = dedupeTextList([...form.imageUrls, url]).slice(
            0,
            MAX_PRODUCT_IMAGE_COUNT,
          );
          successCount += 1;
        } catch (error) {
          failedCount += 1;
          console.error(error);
        }
      }
    } finally {
      isUploadingImage.value = false;
    }

    if (successCount > 0) {
      message.success(
        successCount === 1 ? '图片上传成功' : `已上传 ${successCount} 张图片`,
      );
    }
    if (failedCount > 0) {
      message.error(
        failedCount === 1
          ? '1 张图片上传失败'
          : `${failedCount} 张图片上传失败`,
      );
    }
  }

  async function uploadImage(file: File) {
    await uploadImages([file]);
  }

  function removeImage(index: number) {
    if (index < 0 || index >= form.imageUrls.length) return;
    form.imageUrls = form.imageUrls.filter(
      (_, itemIndex) => itemIndex !== index,
    );
  }

  function setPrimaryImage(index: number) {
    if (index <= 0 || index >= form.imageUrls.length) return;
    const next = [...form.imageUrls];
    const [picked] = next.splice(index, 1);
    if (!picked) return;
    form.imageUrls = [picked, ...next];
  }

  async function loadDetail() {
    if (!storeId.value || !productId.value) {
      clearPageData();
      return;
    }

    isLoading.value = true;
    try {
      const [detailData, categories, specs, addons, labels] = await Promise.all(
        [
          getProductDetailApi({
            storeId: storeId.value,
            productId: productId.value,
          }),
          getProductCategoryListApi(storeId.value),
          getProductSpecListApi({ storeId: storeId.value }),
          getProductAddonGroupListApi({ storeId: storeId.value }),
          getProductLabelListApi({ storeId: storeId.value }),
        ],
      );

      detail.value = detailData;
      categoryOptions.value = categories.map((item) => ({
        label: item.name,
        value: item.id,
      }));
      specTemplateOptions.value = specs;
      addonGroupOptions.value = addons;
      labelOptions.value = labels;

      patchForm(detailData);
      buildSkuRows();
    } catch (error) {
      console.error(error);
      clearPageData();
    } finally {
      isLoading.value = false;
    }
  }

  function sleep(ms: number) {
    return new Promise<void>((resolve) => {
      setTimeout(resolve, ms);
    });
  }

  async function waitForSkuSaveJob(storeIdValue: string, jobId: string) {
    let lastStatus = 'queued';
    let lastErrorMessage: null | string = null;

    for (let i = 0; i < ASYNC_SKU_POLL_MAX_ATTEMPTS; i += 1) {
      try {
        const status = await getProductSkuSaveJobApi({
          storeId: storeIdValue,
          jobId,
        });
        lastStatus = status.status;
        lastErrorMessage = status.errorMessage;
      } catch (error) {
        console.error(error);
        return {
          errorMessage: lastErrorMessage,
          status: lastStatus,
          timedOut: true,
        };
      }

      if (
        lastStatus === 'succeeded' ||
        lastStatus === 'failed' ||
        lastStatus === 'canceled'
      ) {
        return {
          errorMessage: lastErrorMessage,
          status: lastStatus,
          timedOut: false,
        };
      }

      await sleep(ASYNC_SKU_POLL_INTERVAL_MS);
    }

    return {
      errorMessage: lastErrorMessage,
      status: lastStatus,
      timedOut: true,
    };
  }

  async function watchSkuSaveJobInBackground(
    storeIdValue: string,
    productIdValue: string,
    jobId: string,
  ) {
    if (activeSkuSaveJobId && activeSkuSaveJobId !== jobId) {
      message.destroy(`product-sku-save-job-${activeSkuSaveJobId}`);
    }

    activeSkuSaveJobId = jobId;
    const toastKey = `product-sku-save-job-${jobId}`;

    const jobResult = await waitForSkuSaveJob(storeIdValue, jobId);
    if (activeSkuSaveJobId !== jobId) {
      message.destroy(toastKey);
      return;
    }

    if (jobResult.status === 'succeeded') {
      if (storeId.value === storeIdValue && form.id === productIdValue) {
        try {
          const latestDetail = await getProductDetailApi({
            storeId: storeIdValue,
            productId: productIdValue,
          });
          detail.value = latestDetail;
          patchForm(latestDetail);
          buildSkuRows();
        } catch (error) {
          console.error(error);
        }
      }

      message.success({
        content: 'SKU 后台保存完成',
        key: toastKey,
      });
      return;
    }

    if (jobResult.status === 'failed' || jobResult.status === 'canceled') {
      message.error({
        content: jobResult.errorMessage || 'SKU 异步保存失败',
        key: toastKey,
      });
      return;
    }

    if (jobResult.timedOut) {
      message.warning({
        content: 'SKU 仍在后台处理中，请稍后刷新查看',
        key: toastKey,
      });
      return;
    }

    message.warning({
      content: 'SKU 保存状态未知，请稍后刷新查看',
      key: toastKey,
    });
  }

  async function enqueueSkuSaveJobInBackground(
    storeIdValue: string,
    productIdValue: string,
    specTemplateIds: string[],
    skus: Array<{
      attributes: Array<{
        optionId: string;
        templateId: string;
      }>;
      isEnabled: boolean;
      originalPrice: null | number;
      price: number;
      skuCode?: string;
      sortOrder: number;
      stock: number;
    }>,
  ) {
    try {
      const createdJob = await createProductSkuSaveJobApi({
        storeId: storeIdValue,
        productId: productIdValue,
        specTemplateIds,
        skus,
      });
      if (!createdJob?.jobId) {
        message.error('SKU 异步任务创建失败');
        return;
      }

      void watchSkuSaveJobInBackground(
        storeIdValue,
        productIdValue,
        createdJob.jobId,
      );
    } catch (error) {
      console.error(error);
    }
  }

  async function saveDetail() {
    if (!storeId.value || !form.id) return;
    if (!form.name.trim()) {
      message.warning('请输入商品名称');
      return;
    }
    if (!form.categoryId) {
      message.warning('请选择商品分类');
      return;
    }
    if (form.shelfMode === 'scheduled' && !form.timedOnShelfAt) {
      message.warning('请选择定时上架时间');
      return;
    }

    if (form.kind === 'combo') {
      if (form.comboGroups.length === 0) {
        message.warning('套餐至少需要一个分组');
        return;
      }

      for (const group of form.comboGroups) {
        if (!group.name.trim()) {
          message.warning('请填写套餐分组名称');
          return;
        }
        if (group.items.length === 0) {
          message.warning(`分组「${group.name}」至少需要一个商品`);
          return;
        }
        if (group.maxSelect < group.minSelect) {
          message.warning(`分组「${group.name}」最大选择数不能小于最小选择数`);
          return;
        }
      }
    }

    for (const sku of form.skus) {
      if (sku.price < 0 || sku.stock < 0) {
        message.warning('SKU 的售价和库存不能小于 0');
        return;
      }
    }

    isSubmitting.value = true;
    try {
      const normalizedSkus = form.skus.map((item, index) => ({
        skuCode: item.skuCode || undefined,
        price: Math.max(0, Number(Number(item.price || 0).toFixed(2))),
        originalPrice:
          item.originalPrice !== null &&
          item.originalPrice !== undefined &&
          Number(item.originalPrice) > 0
            ? Number(Number(item.originalPrice).toFixed(2))
            : null,
        stock: Math.max(0, Math.floor(Number(item.stock || 0))),
        isEnabled: item.isEnabled,
        sortOrder: Math.max(1, Math.floor(Number(item.sortOrder || index + 1))),
        attributes: item.attributes.map((attr) => ({
          templateId: attr.templateId,
          optionId: attr.optionId,
        })),
      }));

      const normalizedComboGroups =
        form.kind === 'combo'
          ? form.comboGroups.map((group, groupIndex) => ({
              name: group.name.trim(),
              minSelect: Math.max(1, Math.floor(Number(group.minSelect || 1))),
              maxSelect: Math.max(1, Math.floor(Number(group.maxSelect || 1))),
              sortOrder: Math.max(
                1,
                Math.floor(Number(group.sortOrder || groupIndex + 1)),
              ),
              items: group.items.map((item, itemIndex) => ({
                productId: item.productId,
                quantity: Math.max(1, Math.floor(Number(item.quantity || 1))),
                sortOrder: Math.max(
                  1,
                  Math.floor(Number(item.sortOrder || itemIndex + 1)),
                ),
              })),
            }))
          : [];

      const payload = {
        id: form.id,
        storeId: storeId.value,
        categoryId: form.categoryId,
        name: form.name.trim(),
        subtitle: form.subtitle.trim(),
        description: form.description.trim(),
        price: Number(Number(form.price || 0).toFixed(2)),
        originalPrice:
          form.originalPrice !== null &&
          form.originalPrice !== undefined &&
          Number(form.originalPrice) > 0
            ? Number(Number(form.originalPrice).toFixed(2))
            : null,
        stock: Math.max(0, Math.floor(Number(form.stock || 0))),
        status: form.status,
        shelfMode: form.shelfMode,
        timedOnShelfAt:
          form.shelfMode === 'scheduled' && form.timedOnShelfAt
            ? form.timedOnShelfAt
            : undefined,
        imageUrls: [...form.imageUrls],
        sortWeight: Math.max(0, Math.floor(Number(form.sortWeight || 0))),
        warningStock:
          form.warningStock !== null && form.warningStock !== undefined
            ? Math.max(0, Math.floor(Number(form.warningStock)))
            : null,
        packingFee:
          form.packingFee !== null && form.packingFee !== undefined
            ? Math.max(0, Number(Number(form.packingFee).toFixed(2)))
            : null,
        specTemplateIds: [...form.specTemplateIds],
        addonGroupIds: [...form.addonGroupIds],
        labelIds: [...form.labelIds],
        comboGroups: normalizedComboGroups,
        tags: [],
      };

      const asyncSaved = await saveProductAsyncApi(payload);
      if (asyncSaved.productId) {
        form.id = asyncSaved.productId;
      }

      message.success(asyncSaved.message || '商品基础信息已保存');
      if (normalizedSkus.length > 0 && (asyncSaved.productId || form.id)) {
        void enqueueSkuSaveJobInBackground(
          storeId.value,
          asyncSaved.productId || form.id,
          [...form.specTemplateIds],
          normalizedSkus,
        );
      }
    } catch (error) {
      console.error(error);
    } finally {
      isSubmitting.value = false;
    }
  }

  async function toggleSaleStatus(next: ProductStatus) {
    if (next !== 'on_sale' && next !== 'off_shelf') return;
    form.status = next;
    form.shelfMode = next === 'on_sale' ? 'now' : 'draft';
    await saveDetail();
  }

  function setShelfMode(mode: 'draft' | 'now' | 'scheduled') {
    form.shelfMode = mode;
    form.status = mode === 'now' ? 'on_sale' : 'off_shelf';
  }

  async function deleteCurrentProduct() {
    if (!storeId.value || !form.id) return;
    await deleteProductApi({
      storeId: storeId.value,
      productId: form.id,
    });
    message.success('商品已删除');
    router.push('/product/list');
  }

  return {
    deleteCurrentProduct,
    loadDetail,
    removeImage,
    saveDetail,
    setPrimaryImage,
    setShelfMode,
    toggleAddonGroup,
    toggleLabel,
    toggleSaleStatus,
    uploadImage,
    uploadImages,
  };
}
