package com.yhy.module.core.service.resource.impl;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_CALC_BASE_CATEGORY_NOT_FOUND;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_CALC_BASE_INVALID;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_FORMULA_PARSE_ERROR;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_NOT_EXISTS;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_SELF_REFERENCE;
import static com.yhy.module.core.enums.ErrorCodeConstants.RESOURCE_MERGED_SOURCE_NOT_EXISTS;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.yhy.module.core.controller.admin.resource.vo.ResourceMergedPageReqVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceMergedRespVO;
import com.yhy.module.core.controller.admin.resource.vo.ResourceMergedSaveReqVO;
import com.yhy.module.core.dal.dataobject.resource.ResourceItemDO;
import com.yhy.module.core.dal.dataobject.resource.ResourceMergedDO;
import com.yhy.module.core.dal.mysql.resource.ResourceItemMapper;
import com.yhy.module.core.dal.mysql.resource.ResourceMergedMapper;
import com.yhy.module.core.service.resource.ResourceMergedService;
import com.yhy.module.core.util.FormulaEvaluator;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 复合工料机 Service 实现类
 *
 * @author yihuiyong
 */
@Service
@Validated
@Slf4j
public class ResourceMergedServiceImpl implements ResourceMergedService {

    @Resource
    private ResourceMergedMapper resourceMergedMapper;

    @Resource
    private ResourceItemMapper resourceItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createResourceMerged(ResourceMergedSaveReqVO createReqVO) {
        // 校验不允许自己关联自己
        if (createReqVO.getMergedId() != null && createReqVO.getSourceId() != null
                && createReqVO.getMergedId().equals(createReqVO.getSourceId())) {
            throw exception(RESOURCE_MERGED_SELF_REFERENCE);
        }
        
        // 插入
        ResourceMergedDO resourceMerged = BeanUtils.toBean(createReqVO, ResourceMergedDO.class);
        resourceMergedMapper.insert(resourceMerged);
        
        // 触发计算
        calculateMergedPrices(resourceMerged.getMergedId());
        
        // 返回
        return resourceMerged.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateResourceMerged(ResourceMergedSaveReqVO updateReqVO) {
        // 校验存在
        ResourceMergedDO existing = validateResourceMergedExists(updateReqVO.getId());
        
        // 校验不允许自己关联自己
        Long mergedId = updateReqVO.getMergedId() != null ? updateReqVO.getMergedId() : existing.getMergedId();
        Long sourceId = updateReqVO.getSourceId() != null ? updateReqVO.getSourceId() : existing.getSourceId();
        if (mergedId != null && sourceId != null && mergedId.equals(sourceId)) {
            throw exception(RESOURCE_MERGED_SELF_REFERENCE);
        }
        
        // 更新
        ResourceMergedDO updateObj = BeanUtils.toBean(updateReqVO, ResourceMergedDO.class);
        resourceMergedMapper.updateById(updateObj);
        
        // 触发计算（使用更新后的 mergedId）
        calculateMergedPrices(mergedId);
    }

    @Override
    public void deleteResourceMerged(Long id) {
        // 校验存在
        validateResourceMergedExists(id);
        // 删除
        resourceMergedMapper.deleteById(id);
    }

    private ResourceMergedDO validateResourceMergedExists(Long id) {
        ResourceMergedDO merged = resourceMergedMapper.selectById(id);
        if (merged == null) {
            throw exception(RESOURCE_MERGED_NOT_EXISTS);
        }
        return merged;
    }

    @Override
    public ResourceMergedRespVO getResourceMerged(Long id) {
        // 查询数据（JOIN 第四层）
        ResourceMergedRespVO respVO = resourceMergedMapper.selectByIdWithDetails(id);
        if (respVO == null) {
            throw exception(RESOURCE_MERGED_NOT_EXISTS);
        }
        return respVO;
    }

    @Override
    public PageResult<ResourceMergedRespVO> getResourceMergedPage(ResourceMergedPageReqVO pageReqVO) {
        // 计算偏移量
        int offset = (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize();
        
        // 查询数据（JOIN 第四层）
        List<ResourceMergedRespVO> list = resourceMergedMapper.selectPageWithDetails(pageReqVO, offset);
        
        // 查询总数
        Long total = resourceMergedMapper.selectCountWithDetails(pageReqVO);
        
        return new PageResult<>(list, total);
    }

    /**
     * 计算指定 merged_id 的价格
     * 
     * @param mergedId 复合工料机ID
     */
    private void calculateMergedPrices(Long mergedId) {
        log.info("[calculateMergedPrices] 开始计算复合工料机价格，mergedId={}", mergedId);
        
        // 1. 查询该 merged_id 的所有第五层数据
        List<ResourceMergedDO> mergedList = resourceMergedMapper.selectByMergedId(mergedId);
        if (mergedList.isEmpty()) {
            log.warn("[calculateMergedPrices] 未找到第五层数据，mergedId={}", mergedId);
            return;
        }
        
        // 2. 查询所有引用的第四层数据
        List<Long> sourceIds = mergedList.stream()
                .map(ResourceMergedDO::getSourceId)
                .filter(id -> id != null)
                .distinct()
                .collect(Collectors.toList());
        
        if (sourceIds.isEmpty()) {
            log.warn("[calculateMergedPrices] 所有第五层数据的 source_id 都为空，mergedId={}", mergedId);
            return;
        }
        
        Map<Long, ResourceItemDO> sourceMap = resourceItemMapper.selectBatchIds(sourceIds).stream()
                .collect(Collectors.toMap(ResourceItemDO::getId, item -> item));
        
        // 3. 计算4个价格字段的合价
        PriceResult priceResult = calculateTotalPrices(mergedList, sourceMap);
        
        // 4. 更新第四层（merged_id 对应的工料机）的价格
        resourceItemMapper.updatePrices(
                mergedId,
                priceResult.taxExclBasePrice,
                priceResult.taxInclBasePrice,
                priceResult.taxExclCompilePrice,
                priceResult.taxInclCompilePrice
        );
        
        log.info("[calculateMergedPrices] 计算完成，mergedId={}, 除税基价={}, 含税基价={}, 除税编制价={}, 含税编制价={}",
                mergedId, priceResult.taxExclBasePrice, priceResult.taxInclBasePrice,
                priceResult.taxExclCompilePrice, priceResult.taxInclCompilePrice);
    }

    /**
     * 计算总价格
     */
    private PriceResult calculateTotalPrices(List<ResourceMergedDO> mergedList, 
                                             Map<Long, ResourceItemDO> sourceMap) {
        PriceResult result = new PriceResult();
        
        // 按类别分组，用于计算基数公式
        Map<Long, PriceResult> categoryPriceMap = new HashMap<>();
        
        for (ResourceMergedDO merged : mergedList) {
            if (merged.getSourceId() == null) {
                log.warn("[calculateTotalPrices] source_id 为空，跳过，id={}", merged.getId());
                continue;
            }
            
            ResourceItemDO source = sourceMap.get(merged.getSourceId());
            if (source == null) {
                throw exception(RESOURCE_MERGED_SOURCE_NOT_EXISTS);
            }
            
            // 计算单条数据的价格
            PriceResult itemPrice = calculateItemPrice(merged, source, mergedList, sourceMap, categoryPriceMap);
            
            // 累加到总价
            result.add(itemPrice);
            
            // 记录类别价格（用于计算基数）
            if (source.getCategoryId() != null) {
                categoryPriceMap.computeIfAbsent(source.getCategoryId(), k -> new PriceResult()).add(itemPrice);
            }
        }
        
        return result;
    }

    /**
     * 计算单条数据的价格
     */
    private PriceResult calculateItemPrice(ResourceMergedDO merged,
                                           ResourceItemDO source,
                                           List<ResourceMergedDO> allMergedList,
                                           Map<Long, ResourceItemDO> sourceMap,
                                           Map<Long, PriceResult> categoryPriceMap) {
        PriceResult result = new PriceResult();
        
        // 定额消耗量
        BigDecimal quotaConsumption = merged.getQuotaConsumption();
        if (quotaConsumption == null) {
            quotaConsumption = BigDecimal.ZERO;
        }
        
        // 判断是否为百分比单位
        boolean isPercentUnit = "%".equals(source.getUnit());
        
        if (isPercentUnit && source.getCalcBase() != null) {
            // 场景2：单位为"%"，使用计算基数公式
            result = calculateWithCalcBase(merged, source, allMergedList, sourceMap, categoryPriceMap);
        } else {
            // 场景1：普通工料机
            BigDecimal factor = quotaConsumption.divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
            
            result.taxExclBasePrice = multiplyOrZero(source.getTaxExclBasePrice(), factor);
            result.taxInclBasePrice = multiplyOrZero(source.getTaxInclBasePrice(), factor);
            result.taxExclCompilePrice = multiplyOrZero(source.getTaxExclCompilePrice(), factor);
            result.taxInclCompilePrice = multiplyOrZero(source.getTaxInclCompilePrice(), factor);
        }
        
        return result;
    }

    /**
     * 使用计算基数公式计算价格
     */
    @SuppressWarnings("unchecked")
    private PriceResult calculateWithCalcBase(ResourceMergedDO merged,
                                              ResourceItemDO source,
                                              List<ResourceMergedDO> allMergedList,
                                              Map<Long, ResourceItemDO> sourceMap,
                                              Map<Long, PriceResult> categoryPriceMap) {
        PriceResult result = new PriceResult();
        
        Map<String, Object> calcBase = source.getCalcBase();
        if (calcBase == null || !calcBase.containsKey("formula") || !calcBase.containsKey("variables")) {
            throw exception(RESOURCE_MERGED_CALC_BASE_INVALID);
        }
        
        String formula = (String) calcBase.get("formula");
        Map<String, Object> variablesConfig = (Map<String, Object>) calcBase.get("variables");
        
        // 构建变量值映射表（4个价格字段分别计算）
        Map<String, BigDecimal> taxExclBaseVars = new HashMap<>();
        Map<String, BigDecimal> taxInclBaseVars = new HashMap<>();
        Map<String, BigDecimal> taxExclCompileVars = new HashMap<>();
        Map<String, BigDecimal> taxInclCompileVars = new HashMap<>();
        
        for (Map.Entry<String, Object> entry : variablesConfig.entrySet()) {
            String varName = entry.getKey();
            Long categoryId = Long.valueOf(entry.getValue().toString());
            
            // 从类别价格映射表中获取价格
            PriceResult categoryPrice = categoryPriceMap.get(categoryId);
            if (categoryPrice == null) {
                throw exception(RESOURCE_MERGED_CALC_BASE_CATEGORY_NOT_FOUND);
            }
            
            taxExclBaseVars.put(varName, categoryPrice.taxExclBasePrice);
            taxInclBaseVars.put(varName, categoryPrice.taxInclBasePrice);
            taxExclCompileVars.put(varName, categoryPrice.taxExclCompilePrice);
            taxInclCompileVars.put(varName, categoryPrice.taxInclCompilePrice);
        }
        
        // 计算公式结果
        try {
            BigDecimal taxExclBaseSum = FormulaEvaluator.evaluate(formula, taxExclBaseVars);
            BigDecimal taxInclBaseSum = FormulaEvaluator.evaluate(formula, taxInclBaseVars);
            BigDecimal taxExclCompileSum = FormulaEvaluator.evaluate(formula, taxExclCompileVars);
            BigDecimal taxInclCompileSum = FormulaEvaluator.evaluate(formula, taxInclCompileVars);
            
            // 乘以 (定额消耗量 / 100)
            BigDecimal factor = merged.getQuotaConsumption().divide(new BigDecimal("100"), 4, RoundingMode.HALF_UP);
            
            result.taxExclBasePrice = taxExclBaseSum.multiply(factor).setScale(4, RoundingMode.HALF_UP);
            result.taxInclBasePrice = taxInclBaseSum.multiply(factor).setScale(4, RoundingMode.HALF_UP);
            result.taxExclCompilePrice = taxExclCompileSum.multiply(factor).setScale(4, RoundingMode.HALF_UP);
            result.taxInclCompilePrice = taxInclCompileSum.multiply(factor).setScale(4, RoundingMode.HALF_UP);
        } catch (Exception e) {
            log.error("[calculateWithCalcBase] 公式计算失败，formula={}, error={}", formula, e.getMessage());
            throw exception(RESOURCE_MERGED_FORMULA_PARSE_ERROR);
        }
        
        return result;
    }

    /**
     * 安全乘法（处理 null 值）
     */
    private BigDecimal multiplyOrZero(BigDecimal value, BigDecimal factor) {
        if (value == null) {
            return BigDecimal.ZERO;
        }
        return value.multiply(factor).setScale(4, RoundingMode.HALF_UP);
    }

    /**
     * 价格结果对象
     */
    private static class PriceResult {
        BigDecimal taxExclBasePrice = BigDecimal.ZERO;
        BigDecimal taxInclBasePrice = BigDecimal.ZERO;
        BigDecimal taxExclCompilePrice = BigDecimal.ZERO;
        BigDecimal taxInclCompilePrice = BigDecimal.ZERO;
        
        void add(PriceResult other) {
            this.taxExclBasePrice = this.taxExclBasePrice.add(other.taxExclBasePrice);
            this.taxInclBasePrice = this.taxInclBasePrice.add(other.taxInclBasePrice);
            this.taxExclCompilePrice = this.taxExclCompilePrice.add(other.taxExclCompilePrice);
            this.taxInclCompilePrice = this.taxInclCompilePrice.add(other.taxInclCompilePrice);
        }
    }
}
