package com.jeesharp.business.modules.mall.validator;

import com.jeesharp.business.modules.common.enums.DisabledEnabledEnum;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.jeesharp.business.modules.mall.dto.MallProductSaveDTO;
import com.jeesharp.business.modules.mall.dto.MallSkuSaveDTO;
import com.jeesharp.business.modules.mall.dto.MallSpuExtAttrSaveDTO;
import com.jeesharp.business.modules.mall.entity.MallProductTemplateItem;
import com.jeesharp.business.modules.mall.enums.MallProductTemplateItemTypeEnum;
import com.jeesharp.business.modules.mall.enums.MallSpuShipTimeTypeEnum;
import com.jeesharp.business.modules.mall.entity.MallBrand;
import com.jeesharp.business.modules.mall.entity.MallCategory;
import com.jeesharp.business.modules.mall.entity.MallSpecValue;
import com.jeesharp.business.modules.mall.enums.MallCategoryStatusEnum;

import com.jeesharp.business.modules.mall.service.MallBrandService;
import com.jeesharp.business.modules.mall.service.MallCategoryService;
import com.jeesharp.business.modules.common.constants.PlatformTenantConstants;
import com.jeesharp.business.modules.mall.service.MallProductTemplateItemService;
import com.jeesharp.business.modules.mall.service.MallSpecValueService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * SPU 数据验证器：基础校验及「分类绑定模板」下的规格与扩展属性约束。
 *
 * @author jeesharp
 * @since 2026-05-15
 */
@Slf4j
@Component
@AllArgsConstructor
public class MallSpuValidator {

    private final MallCategoryService mallCategoryService;
    private final MallBrandService mallBrandService;
    private final MallProductTemplateItemService mallProductTemplateItemService;
    private final MallSpecValueService mallSpecValueService;

    /**
     * 验证商品保存数据
     */
    public void validateProductData(MallProductSaveDTO dto) {
        log.debug("验证商品数据: {}", dto.getSpuName());

        validateBasicInfo(dto);
        validateCategory(dto);
        validateBrand(dto);
        validateNameUniqueness(dto);
        if (dto.getSkuList() != null) {
            validateSkuList(dto.getSkuList());
        }
        validateSkuSpecValues(dto);
        validateTemplateConstraints(dto);
    }

    private void validateBasicInfo(MallProductSaveDTO dto) {
        if (StringUtils.isEmpty(dto.getSpuName())) {
            throw new IllegalArgumentException("商品名称不能为空");
        }
        if (dto.getSpuName().length() > 128) {
            throw new IllegalArgumentException("商品名称长度不能超过128个字符");
        }
        if (StringUtils.isEmpty(dto.getCategoryId())) {
            throw new IllegalArgumentException("商品分类不能为空");
        }
        if (dto.getStatus() == null || (dto.getStatus() != 0 && dto.getStatus() != 1)) {
            throw new IllegalArgumentException("商品状态只能是0(下架)或1(上架)");
        }
        if (dto.getShipTimeType() != null
            && MallSpuShipTimeTypeEnum.fromValue(dto.getShipTimeType()) == null) {
            throw new IllegalArgumentException("发货时效取值无效");
        }
        if (dto.getFreightAmount() != null && dto.getFreightAmount().compareTo(BigDecimal.ZERO) < 0) {
            throw new IllegalArgumentException("运费不能为负数");
        }
    }

    private void validateCategory(MallProductSaveDTO dto) {
        MallCategory category = mallCategoryService.get(dto.getCategoryId());
        if (category == null) {
            throw new IllegalArgumentException("商品分类不存在");
        }
        if (!PlatformTenantConstants.PLATFORM_TENANT_CODE.equals(category.getTenantCode())) {
            throw new IllegalArgumentException("商品分类无效，请选择平台维护的类目");
        }
        if (!MallCategoryStatusEnum.ENABLED.getValue().equals(category.getStatus())) {
            throw new IllegalArgumentException("商品分类已禁用，请重新选择");
        }
        if (mallCategoryService.hasChildCategory(category.getId())) {
            throw new IllegalArgumentException("请选择末级商品分类");
        }
    }

    private void validateBrand(MallProductSaveDTO dto) {
        if (StringUtils.isEmpty(dto.getBrandId())) {
            return;
        }
        MallBrand brand = mallBrandService.get(dto.getBrandId());
        if (brand == null) {
            throw new IllegalArgumentException("商品品牌不存在");
        }
        if (!PlatformTenantConstants.PLATFORM_TENANT_CODE.equals(brand.getTenantCode())) {
            throw new IllegalArgumentException("商品品牌无效，请选择平台维护的品牌");
        }
        if (!DisabledEnabledEnum.ENABLED.getValue().equals(brand.getStatus())) {
            throw new IllegalArgumentException("商品品牌已禁用，请重新选择");
        }
    }

    private void validateNameUniqueness(MallProductSaveDTO dto) {
        log.debug("验证商品名称重复性: {}", dto.getSpuName());
    }

    private void validateSkuList(java.util.List<MallSkuSaveDTO> skuList) {
        if (skuList.isEmpty()) {
            throw new IllegalArgumentException("至少需要一个SKU");
        }

        for (int i = 0; i < skuList.size(); i++) {
            MallSkuSaveDTO sku = skuList.get(i);
            validateSku(sku, i + 1);
        }
    }

    private void validateSku(MallSkuSaveDTO sku, int index) {
        if (sku.getPrice() == null || sku.getPrice().compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalArgumentException(String.format("第%d个SKU的价格必须大于0", index));
        }
        if (sku.getStock() == null || sku.getStock() < 0) {
            throw new IllegalArgumentException(String.format("第%d个SKU的库存不能为负数", index));
        }
        if (sku.getStatus() == null || (sku.getStatus() != 0 && sku.getStatus() != 1)) {
            throw new IllegalArgumentException(String.format("第%d个SKU的状态只能是0(禁用)或1(启用)", index));
        }

        log.debug("验证SKU {}: 价格={}, 库存={}, 状态={}", index, sku.getPrice(), sku.getStock(), sku.getStatus());
    }

    /**
     * 校验 SKU 引用的规格值须属于当前商户租户，且规格维度与 SPU 所选一致；多规格组合不可重复。
     */
    private void validateSkuSpecValues(MallProductSaveDTO dto) {
        if (dto.getSkuList() == null || dto.getSkuList().isEmpty()) {
            return;
        }
        Set<String> chosenSpecIds = dto.getSpecIds() == null
            ? Set.of()
            : dto.getSpecIds().stream().filter(StrUtil::isNotBlank).map(String::trim).collect(Collectors.toSet());

        List<String> allValueIds = dto.getSkuList().stream()
            .filter(s -> s.getSpecValueIds() != null)
            .flatMap(s -> s.getSpecValueIds().stream())
            .filter(StrUtil::isNotBlank)
            .map(String::trim)
            .distinct()
            .collect(Collectors.toList());
        if (allValueIds.isEmpty()) {
            return;
        }

        List<MallSpecValue> values = mallSpecValueService.listByIdsForCurrentTenant(allValueIds);
        Map<String, MallSpecValue> byId = values.stream()
            .collect(Collectors.toMap(MallSpecValue::getId, v -> v, (a, b) -> a));
        if (byId.size() != allValueIds.size()) {
            throw new IllegalArgumentException("存在无效或非本商户的规格值，请重新选择或添加");
        }

        for (MallSpecValue v : values) {
            if (!DisabledEnabledEnum.ENABLED.getValue().equals(v.getStatus())) {
                throw new IllegalArgumentException("规格值已禁用：" + v.getSpecValue());
            }
            if (!chosenSpecIds.isEmpty() && !chosenSpecIds.contains(v.getSpecId())) {
                throw new IllegalArgumentException("规格值与商品所选规格维度不一致");
            }
        }

        Set<String> comboSigs = new HashSet<>();
        for (MallSkuSaveDTO sku : dto.getSkuList()) {
            if (CollUtil.isEmpty(sku.getSpecValueIds())) {
                continue;
            }
            List<String> combo = sku.getSpecValueIds().stream()
                .filter(StrUtil::isNotBlank)
                .map(String::trim)
                .sorted()
                .collect(Collectors.toList());
            String sig = String.join(",", combo);
            if (!comboSigs.add(sig)) {
                throw new IllegalArgumentException("存在重复的规格组合，请合并 SKU 行");
            }
        }
    }

    /**
     * 若分类绑定了发布模板，则校验所选规格在模板允许范围内，且必填扩展属性在 {@code extAttrs} 中有非空值。
     */
    private void validateTemplateConstraints(MallProductSaveDTO dto) {
        String templateId = mallCategoryService.resolveInheritedTemplateId(dto.getCategoryId());
        if (StrUtil.isBlank(templateId)) {
            return;
        }
        List<MallProductTemplateItem> lines = mallProductTemplateItemService.listByTemplateId(templateId);
        if (CollUtil.isEmpty(lines)) {
            return;
        }

        List<String> allowedSpecIds = lines.stream()
            .filter(i -> MallProductTemplateItemTypeEnum.SPEC.getValue().equals(i.getItemType()))
            .map(MallProductTemplateItem::getSpecId)
            .filter(StrUtil::isNotBlank)
            .collect(Collectors.toList());

        if (!allowedSpecIds.isEmpty()) {
            List<String> chosen = dto.getSpecIds() == null ? List.of() : dto.getSpecIds();
            for (String sid : chosen) {
                if (!allowedSpecIds.contains(sid)) {
                    throw new IllegalArgumentException("所选规格不在当前分类绑定模板的允许范围内");
                }
            }
        }

        List<MallProductTemplateItem> attrLines = lines.stream()
            .filter(i -> MallProductTemplateItemTypeEnum.ATTR.getValue().equals(i.getItemType()))
            .collect(Collectors.toList());
        if (attrLines.isEmpty()) {
            return;
        }

        Map<String, String> valueByKey = extAttrValueMap(dto);

        for (MallProductTemplateItem line : attrLines) {
            if (!Integer.valueOf(1).equals(line.getRequiredFlag())) {
                continue;
            }
            String key = line.getAttrKey();
            if (StrUtil.isBlank(key)) {
                continue;
            }
            String v = valueByKey.get(key.trim());
            if (StrUtil.isBlank(v)) {
                throw new IllegalArgumentException("请填写扩展属性：" + line.getAttrName());
            }
        }
    }

    private static Map<String, String> extAttrValueMap(MallProductSaveDTO dto) {
        Map<String, String> map = new LinkedHashMap<>();
        if (dto.getExtAttrs() == null) {
            return map;
        }
        for (MallSpuExtAttrSaveDTO row : dto.getExtAttrs()) {
            if (row == null || StrUtil.isBlank(row.getAttrKey())) {
                continue;
            }
            String v = row.getAttrValue() == null ? "" : row.getAttrValue().trim();
            map.put(row.getAttrKey().trim(), v);
        }
        return map;
    }
}
