package com.jeesharp.business.modules.mall.service.impl;

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

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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.jeesharp.business.modules.mall.dto.MallProductSaveDTO;
import com.jeesharp.business.modules.mall.dto.MallSkuSaveDTO;
import com.jeesharp.business.modules.mall.dto.MallSpuSaveDTO;
import com.jeesharp.business.modules.mall.entity.MallSku;
import com.jeesharp.business.modules.mall.entity.MallSpu;
import com.jeesharp.business.modules.mall.entity.MallSpuSpec;
import com.jeesharp.business.modules.mall.entity.MallSpuTag;
import com.jeesharp.business.modules.mall.entity.MallTag;

import com.jeesharp.business.modules.mall.enums.MallSpuAuditStatusEnum;

import com.jeesharp.business.modules.mall.mapper.MallSkuMapper;
import com.jeesharp.business.modules.mall.service.MallSkuService;
import com.jeesharp.business.modules.mall.service.MallSpuExtAttrService;
import com.jeesharp.business.modules.mall.service.MallSpuService;
import com.jeesharp.business.modules.mall.service.MallSpuSpecService;
import com.jeesharp.business.modules.mall.service.MallSpuTagService;
import com.jeesharp.business.modules.mall.service.MallTagService;
import com.jeesharp.business.modules.mall.generator.MallSpuCodeGenerator;
import com.jeesharp.business.modules.mall.validator.MallSpuValidator;
import com.jeesharp.business.modules.mall.vo.MallSkuQueryVO;
import com.jeesharp.business.modules.mall.vo.MallSpuSpecQueryVO;
import com.jeesharp.business.modules.mall.vo.MallSpuTagQueryVO;
import com.jeesharp.framework.exception.BizErrorException;
import com.jeesharp.framework.mybatis.core.service.CrudService;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 商品SKU Service 实现类
 * 包含商品相关的业务逻辑
 */
@Slf4j
@Service
@AllArgsConstructor
@Transactional(readOnly = true)
public class MallSkuServiceImpl extends CrudService<MallSkuMapper, MallSku, MallSkuQueryVO> implements MallSkuService {

    private static final String IDS_SEPARATOR = ",";

    private final MallSpuService mallSpuService;
    private final MallSpuSpecService mallSpuSpecService;
    private final MallSpuValidator mallSpuValidator;
    private final MallSpuCodeGenerator mallSpuCodeGenerator;
    private final MallSpuExtAttrService mallSpuExtAttrService;
    private final MallSpuTagService mallSpuTagService;
    private final MallTagService mallTagService;

    /**
     * 执行商品保存业务逻辑
     */
    @Transactional
    @Override
    public void executeSaveProduct(MallProductSaveDTO dto, boolean productAuditEnabled) {
        log.info("执行商品保存业务逻辑: {}, productAuditEnabled={}", dto.getSpuName(), productAuditEnabled);

        boolean isNew = StringUtils.isEmpty(dto.getSpuId());

        // 处理SPU信息
        MallSpu spu = createOrUpdateSpu(dto, isNew, productAuditEnabled);
        mallSpuService.save(spu);
        mallSpuExtAttrService.replaceForSpu(spu.getId(), dto.getExtAttrs());

        // 处理SKU信息
        if (dto.getSkuList() != null && !dto.getSkuList().isEmpty()) {
            if (!isNew) {
                reconcileSkusBeforeSave(spu.getId(), dto.getSkuList());
            }
            saveSkuList(dto.getSkuList(), spu.getId());
        }

        // 处理规格关联
        if (dto.getSpecIds() != null && !dto.getSpecIds().isEmpty()) {
            saveSpuSpecRelations(spu.getId(), dto.getSpecIds());
        }

        // 处理标签关联（全量替换，空列表表示清空）
        if (dto.getTagIds() != null) {
            saveSpuTagRelations(spu.getId(), dto.getTagIds());
        }

        log.info("商品保存业务逻辑执行完成: {}, ID: {}", dto.getSpuName(), spu.getId());
    }

    /**
     * 数据验证（委托给验证器）
     */
    @Override
    public void validateProductData(MallProductSaveDTO dto) {
        log.debug("调用验证器进行商品数据验证: {}", dto.getSpuName());
        mallSpuValidator.validateProductData(dto);
    }

    /**
     * 创建或更新SPU
     */
    @Override
    public MallSpu createOrUpdateSpu(MallProductSaveDTO dto, boolean isNew, boolean productAuditEnabled) {
        log.debug("创建或更新SPU: {}, isNew: {}, productAuditEnabled={}", dto.getSpuName(), isNew, productAuditEnabled);

        MallSpu spu;

        if (isNew) {
            spu = new MallSpu();
            // 生成商品编码
            if (StringUtils.isEmpty(dto.getSpuCode())) {
                dto.setSpuCode(generateSpuCode());
            }
            // 设置默认值
            spu.setVirtualSales(dto.getVirtualSales() != null ? dto.getVirtualSales() : 0);
            spu.setSortOrder(dto.getSortOrder() != null ? dto.getSortOrder() : 0);
            applyShelfAndAuditOnCreate(spu, dto, productAuditEnabled);
        } else {
            spu = mallSpuService.get(dto.getSpuId());
            if (spu == null) {
                throw new IllegalArgumentException("商品不存在");
            }
            log.debug("更新现有商品: {}", spu.getId());
        }

        // 设置基本信息
        spu.setSpuName(dto.getSpuName());
        spu.setSpuCode(dto.getSpuCode());
        spu.setCategoryId(dto.getCategoryId());
        spu.setBrandId(dto.getBrandId());
        spu.setMainImage(dto.getMainImage());
        spu.setImages(dto.getImages());
        spu.setDetail(dto.getDetail());
        spu.setShipTimeType(dto.getShipTimeType());
        spu.setFreightAmount(dto.getFreightAmount());
        spu.setFreightTemplateId(dto.getFreightTemplateId());
        spu.setVirtualSales(dto.getVirtualSales());
        spu.setSortOrder(dto.getSortOrder());
        spu.setMerchantId(dto.getMerchantId());

        if (!isNew) {
            applyShelfAndAuditOnUpdate(spu, dto, productAuditEnabled);
        }

        return spu;
    }

    private void applyShelfAndAuditOnCreate(MallSpu spu, MallProductSaveDTO dto, boolean productAuditEnabled) {
        if (productAuditEnabled) {
            spu.setStatus(ShelfStatusEnum.OFFLINE.getValue());
            spu.setAuditStatus(MallSpuAuditStatusEnum.PENDING.getValue());
            log.debug("新商品：开启审核，下架待审");
            return;
        }
        spu.setAuditStatus(MallSpuAuditStatusEnum.PASSED.getValue());
        Integer shelfStatus = dto.getStatus() != null ? dto.getStatus() : ShelfStatusEnum.ONLINE.getValue();
        spu.setStatus(shelfStatus);
        log.debug("新商品：未开启审核，直接生效 status={}", shelfStatus);
    }

    private void applyShelfAndAuditOnUpdate(MallSpu spu, MallProductSaveDTO dto, boolean productAuditEnabled) {
        if (productAuditEnabled) {
            spu.setStatus(ShelfStatusEnum.OFFLINE.getValue());
            spu.setAuditStatus(MallSpuAuditStatusEnum.PENDING.getValue());
            spu.setAuditRemark(null);
            spu.setAuditTime(null);
            spu.setAuditBy(null);
            log.debug("编辑商品：重新进入待审核");
            return;
        }
        spu.setAuditStatus(MallSpuAuditStatusEnum.PASSED.getValue());
        spu.setStatus(dto.getStatus() != null ? dto.getStatus() : spu.getStatus());
    }

    /**
     * 生成商品编码（委托给编码生成器）
     */
    @Override
    public String generateSpuCode() {
        return mallSpuCodeGenerator.generateSpuCode();
    }

    /**
     * 保存SKU列表
     */
    @Override
    public void saveSkuList(List<MallSkuSaveDTO> skuList, String spuId) {
        log.debug("保存SKU列表, SPU ID: {}, SKU数量: {}", spuId, skuList.size());

        for (MallSkuSaveDTO skuDto : skuList) {
            MallSku sku = createSkuFromDto(skuDto, spuId);
            if (StrUtil.isNotBlank(sku.getId()) && get(sku.getId()) != null) {
                update(sku);
            } else {
                save(sku);
            }
            log.debug("保存SKU: {}", sku.getSkuName());
        }
    }

    /**
     * 从DTO创建SKU实体
     */
    @Override
    public MallSku createSkuFromDto(MallSkuSaveDTO dto, String spuId) {
        MallSku sku = new MallSku();
        sku.setId(dto.getId());
        sku.setSpuId(spuId);
        sku.setSkuName(dto.getSkuName());
        sku.setSkuCode(dto.getSkuCode());
        sku.setSpecInfo(dto.getSpecInfo());
        if (CollUtil.isNotEmpty(dto.getSpecValueIds())) {
            sku.setSpecValueIds(JSONUtil.toJsonStr(dto.getSpecValueIds()));
        } else {
            sku.setSpecValueIds(null);
        }
        sku.setPrice(dto.getPrice());
        sku.setOriginalPrice(dto.getOriginalPrice());
        sku.setStock(dto.getStock());
        sku.setStockWarn(dto.getStockWarn() != null ? dto.getStockWarn() : 10);
        sku.setBarCode(dto.getBarCode());
        sku.setImage(dto.getImage());
        sku.setLimitPerUser(dto.getLimitPerUser() != null ? dto.getLimitPerUser() : 0);
        sku.setStatus(dto.getStatus() != null ? dto.getStatus() : 1);
        return sku;
    }

    /**
     * 更新商品时删除未再提交的 SKU，避免规格矩阵重算后遗留旧行。
     *
     * @param spuId   SPU 主键
     * @param skuList 本次提交的 SKU 列表
     */
    private void reconcileSkusBeforeSave(String spuId, List<MallSkuSaveDTO> skuList) {
        MallSkuQueryVO skuQuery = new MallSkuQueryVO();
        skuQuery.setSpuId(spuId);
        List<MallSku> existing = findList(skuQuery);
        if (CollUtil.isEmpty(existing)) {
            return;
        }
        Set<String> keepIds = skuList.stream()
            .map(MallSkuSaveDTO::getId)
            .filter(StrUtil::isNotBlank)
            .collect(Collectors.toSet());
        for (MallSku e : existing) {
            if (!keepIds.contains(e.getId())) {
                delete(e.getId());
            }
        }
    }

    /**
     * 保存SPU规格关联
     */
    @Override
    public void saveSpuSpecRelations(String spuId, List<String> specIds) {
        log.debug("保存SPU规格关联, SPU ID: {}, 规格数量: {}", spuId, specIds.size());

        // 先删除原有关联
        MallSpuSpecQueryVO query = new MallSpuSpecQueryVO();
        query.setSpuId(spuId);
        List<MallSpuSpec> existingSpecs = mallSpuSpecService.findList(query);
        if (!existingSpecs.isEmpty()) {
            List<String> ids = existingSpecs.stream().map(MallSpuSpec::getId).collect(Collectors.toList());
            mallSpuSpecService.batchDelete(ids);
            log.debug("删除原有规格关联: {}", ids.size());
        }

        // 保存新的关联
        for (String specId : specIds) {
            MallSpuSpec spuSpec = new MallSpuSpec();
            spuSpec.setSpuId(spuId);
            spuSpec.setSpecId(specId);
            spuSpec.setSortOrder(0);
            mallSpuSpecService.save(spuSpec);
        }

        log.debug("保存新规格关联完成: {}", specIds.size());
    }

    /**
     * 保存 SPU 标签关联（先删后插，冗余标签名称便于列表展示）
     */
    @Override
    public void saveSpuTagRelations(String spuId, List<String> tagIds) {
        log.debug("保存SPU标签关联, SPU ID: {}, 标签数量: {}", spuId, tagIds != null ? tagIds.size() : 0);

        MallSpuTagQueryVO query = new MallSpuTagQueryVO();
        query.setSpuId(spuId);
        List<MallSpuTag> existingTags = mallSpuTagService.findList(query);
        if (!existingTags.isEmpty()) {
            List<String> ids = existingTags.stream().map(MallSpuTag::getId).collect(Collectors.toList());
            mallSpuTagService.batchDelete(ids);
            log.debug("删除原有标签关联: {}", ids.size());
        }

        if (CollUtil.isEmpty(tagIds)) {
            return;
        }

        int sortOrder = 0;
        for (String tagId : tagIds) {
            if (StrUtil.isBlank(tagId)) {
                continue;
            }
            String normalizedTagId = tagId.trim();
            MallSpuTag spuTag = new MallSpuTag();
            spuTag.setSpuId(spuId);
            spuTag.setTagId(normalizedTagId);
            MallTag tag = mallTagService.get(normalizedTagId);
            if (tag != null) {
                spuTag.setTagName(tag.getTagName());
            }
            spuTag.setSortOrder(sortOrder++);
            mallSpuTagService.save(spuTag);
        }

        log.debug("保存新标签关联完成: {}", sortOrder);
    }

    /**
     * 删除商品（包含级联删除）
     */
    @Transactional
    @Override
    public void deleteProduct(String spuId) {
        log.info("删除商品: {}", spuId);

        // 删除SKU - 查找并删除属于该SPU的所有SKU
        MallSkuQueryVO skuQuery = new MallSkuQueryVO();
        skuQuery.setSpuId(spuId);
        List<MallSku> skus = findList(skuQuery);
        if (!skus.isEmpty()) {
            List<String> skuIds = skus.stream().map(MallSku::getId).collect(Collectors.toList());
            batchDelete(skuIds);
            log.debug("删除SKU: {}", skuIds.size());
        }

        // 删除规格关联
        MallSpuSpecQueryVO query = new MallSpuSpecQueryVO();
        query.setSpuId(spuId);
        List<MallSpuSpec> specs = mallSpuSpecService.findList(query);
        if (!specs.isEmpty()) {
            List<String> specIds = specs.stream().map(MallSpuSpec::getId).collect(Collectors.toList());
            mallSpuSpecService.batchDelete(specIds);
            log.debug("删除规格关联: {}", specIds.size());
        }

        mallSpuExtAttrService.deleteBySpuId(spuId);

        // 删除标签关联
        MallSpuTagQueryVO tagQuery = new MallSpuTagQueryVO();
        tagQuery.setSpuId(spuId);
        List<MallSpuTag> spuTags = mallSpuTagService.findList(tagQuery);
        if (!spuTags.isEmpty()) {
            List<String> spuTagIds = spuTags.stream().map(MallSpuTag::getId).collect(Collectors.toList());
            mallSpuTagService.batchDelete(spuTagIds);
            log.debug("删除标签关联: {}", spuTagIds.size());
        }

        // 删除SPU
        mallSpuService.delete(spuId);

        log.info("商品删除完成: {}", spuId);
    }

    @Override
    @Transactional
    public void createSimpleProduct(MallSpuSaveDTO dto, boolean productAuditEnabled) {
        MallProductSaveDTO productDTO = convertSimpleToFull(dto);
        validateProductData(productDTO);
        executeSaveProduct(productDTO, productAuditEnabled);
    }

    @Override
    @Transactional
    public void updateSimpleProduct(MallSpuSaveDTO dto, boolean productAuditEnabled) {
        MallProductSaveDTO productDTO = convertSimpleToFull(dto);
        validateProductData(productDTO);
        executeSaveProduct(productDTO, productAuditEnabled);
    }

    @Override
    @Transactional
    public void deleteProducts(String ids) {
        for (String spuId : Arrays.asList(ids.split(IDS_SEPARATOR))) {
            deleteProduct(spuId);
        }
    }

    @Override
    public BigDecimal getMinSalePrice(String spuId) {
        return listEnabledSkus(spuId).stream()
                .map(MallSku::getPrice)
                .filter(p -> p != null && p.compareTo(BigDecimal.ZERO) > 0)
                .min(BigDecimal::compareTo)
                .orElse(null);
    }

    @Override
    public List<MallSku> listEnabledSkus(String spuId) {
        MallSkuQueryVO query = new MallSkuQueryVO();
        query.setSpuId(spuId);
        query.setStatus(DisabledEnabledEnum.ENABLED.getValue());
        return findList(query);
    }

    @Override
    @Transactional(readOnly = false)
    public void decreaseStock(String skuId, int quantity) {
        if (StrUtil.isBlank(skuId) || quantity < 1) {
            throw new BizErrorException("库存参数无效");
        }
        MallSku sku = get(skuId);
        if (sku == null) {
            throw new BizErrorException("SKU不存在");
        }
        if (!DisabledEnabledEnum.ENABLED.getValue().equals(sku.getStatus())) {
            throw new BizErrorException("SKU已下架");
        }
        int st = sku.getStock() == null ? 0 : sku.getStock();
        if (st < quantity) {
            throw new BizErrorException("库存不足");
        }
        sku.setStock(st - quantity);
        update(sku);
    }

    @Override
    @Transactional(readOnly = false)
    public void increaseStock(String skuId, int quantity) {
        if (StrUtil.isBlank(skuId) || quantity < 1) {
            return;
        }
        MallSku sku = get(skuId);
        if (sku == null) {
            return;
        }
        int st = sku.getStock() == null ? 0 : sku.getStock();
        sku.setStock(st + quantity);
        update(sku);
    }

    private MallProductSaveDTO convertSimpleToFull(MallSpuSaveDTO dto) {
        MallProductSaveDTO fullDTO = new MallProductSaveDTO();
        fullDTO.setSpuId(dto.getId());
        fullDTO.setSpuName(dto.getSpuName());
        fullDTO.setSpuCode(dto.getSpuCode());
        fullDTO.setCategoryId(dto.getCategoryId());
        fullDTO.setBrandId(dto.getBrandId());
        fullDTO.setMainImage(dto.getMainImage());
        fullDTO.setImages(dto.getImages());
        fullDTO.setDetail(dto.getDetail());
        fullDTO.setShipTimeType(dto.getShipTimeType());
        fullDTO.setFreightAmount(dto.getFreightAmount());
        fullDTO.setFreightTemplateId(dto.getFreightTemplateId());
        fullDTO.setExtAttrs(dto.getExtAttrs());
        fullDTO.setVirtualSales(dto.getVirtualSales());
        fullDTO.setSortOrder(dto.getSortOrder());
        fullDTO.setStatus(dto.getStatus());
        fullDTO.setMerchantId(dto.getMerchantId());
        return fullDTO;
    }

    @Override
    public List<String> findIdsBySkuNameLike(String skuName) {
        if (StrUtil.isBlank(skuName)) {
            return List.of();
        }
        LambdaQueryWrapper<MallSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MallSku::getDelFlag, "0");
        wrapper.like(MallSku::getSkuName, skuName.trim());
        return getBaseMapper().selectList(wrapper).stream()
            .map(MallSku::getId)
            .filter(StrUtil::isNotBlank)
            .distinct()
            .collect(Collectors.toList());
    }

    @Override
    public Map<String, String> mapSkuNameByIds(List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyMap();
        }
        List<String> idList = ids.stream().filter(StrUtil::isNotBlank).map(String::trim).distinct().collect(Collectors.toList());
        if (idList.isEmpty()) {
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<MallSku> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MallSku::getDelFlag, "0");
        wrapper.in(MallSku::getId, idList);
        return getBaseMapper().selectList(wrapper).stream()
            .filter(s -> s != null && StrUtil.isNotBlank(s.getId()))
            .collect(Collectors.toMap(MallSku::getId, s -> StrUtil.blankToDefault(s.getSkuName(), ""), (a, b) -> a));
    }
}
