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

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.yhy.module.core.controller.admin.quota.vo.QuotaRateFieldRespVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaRateItemRespVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaRateItemSaveReqVO;
import com.yhy.module.core.controller.admin.quota.vo.QuotaRateValueRulesReqVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaRateFieldDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaRateItemDO;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaRateFieldMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaRateItemMapper;
import com.yhy.module.core.service.quota.QuotaRateFieldService;
import com.yhy.module.core.service.quota.QuotaRateItemService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yhy.module.core.enums.ErrorCodeConstants.*;

/**
 * 定额费率项 Service 实现
 */
@Service
@RequiredArgsConstructor
public class QuotaRateItemServiceImpl implements QuotaRateItemService {

    private final QuotaRateItemMapper rateItemMapper;
    private final QuotaRateFieldMapper rateFieldMapper;
    private final QuotaRateFieldService rateFieldService;
    private final QuotaCatalogItemMapper catalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createRateItem(QuotaRateItemSaveReqVO createReqVO) {
        // 1. 验证模式节点
        validateRateModeNode(createReqVO.getCatalogItemId());
        
        // 2. 验证父节点
        validateParent(createReqVO.getParentId(), createReqVO.getCatalogItemId());
        
        // 3. 计算层级
        Integer level = calculateLevel(createReqVO.getParentId());
        if (level > 3) {
            throw exception(QUOTA_RATE_ITEM_LEVEL_EXCEED);
        }
        
        // 3. 设置排序值
        Integer sortOrder = createReqVO.getSortOrder();
        if (sortOrder == null) {
            sortOrder = rateItemMapper.selectMaxSortOrder(createReqVO.getCatalogItemId(), createReqVO.getParentId()) + 1;
        }
        
        // 4. 创建费率项
        QuotaRateItemDO rateItem = BeanUtils.toBean(createReqVO, QuotaRateItemDO.class);
        rateItem.setLevel(level);
        rateItem.setSortOrder(sortOrder);
        if (rateItem.getValueMode() == null) {
            rateItem.setValueMode(QuotaRateItemDO.VALUE_MODE_STATIC);
        }
        if (rateItem.getIsEditable() == null) {
            rateItem.setIsEditable(false);
        }
        
        rateItemMapper.insert(rateItem);
        return rateItem.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateRateItem(QuotaRateItemSaveReqVO updateReqVO) {
        // 1. 验证存在
        QuotaRateItemDO existItem = validateRateItemExists(updateReqVO.getId());
        
        // 2. 如果修改了父节点，需要验证
        if (updateReqVO.getParentId() != null && 
            !Objects.equals(existItem.getParentId(), updateReqVO.getParentId())) {
            validateParent(updateReqVO.getParentId(), existItem.getCatalogItemId());
            // 重新计算层级
            Integer newLevel = calculateLevel(updateReqVO.getParentId());
            if (newLevel > 3) {
                throw exception(QUOTA_RATE_ITEM_LEVEL_EXCEED);
            }
            updateReqVO.setSortOrder(newLevel);
        }
        
        // 3. 更新
        QuotaRateItemDO updateObj = BeanUtils.toBean(updateReqVO, QuotaRateItemDO.class);
        rateItemMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteRateItem(Long id) {
        // 1. 验证存在
        validateRateItemExists(id);
        
        // 2. 验证没有子节点
        if (rateItemMapper.hasChildren(id)) {
            throw exception(QUOTA_RATE_ITEM_HAS_CHILDREN);
        }
        
        // 3. 删除字段绑定
        rateFieldService.deleteByRateItemId(id);
        
        // 4. 删除费率项
        rateItemMapper.deleteById(id);
    }

    @Override
    public QuotaRateItemDO getRateItem(Long id) {
        return rateItemMapper.selectById(id);
    }

    @Override
    public QuotaRateItemRespVO getRateItemDetail(Long id) {
        QuotaRateItemDO rateItem = validateRateItemExists(id);
        QuotaRateItemRespVO respVO = BeanUtils.toBean(rateItem, QuotaRateItemRespVO.class);
        
        // 查询字段绑定
        List<QuotaRateFieldRespVO> fields = rateFieldService.getRateFieldList(id);
        respVO.setFields(fields);
        respVO.setHasChildren(rateItemMapper.hasChildren(id));
        
        return respVO;
    }

    @Override
    public List<QuotaRateItemRespVO> getRateItemList(Long catalogItemId, Long parentId) {
        List<QuotaRateItemDO> list;
        if (parentId == null) {
            list = rateItemMapper.selectRootListByCatalogItemId(catalogItemId);
        } else {
            list = rateItemMapper.selectListByParentId(parentId);
        }
        
        // 转换并查询字段绑定
        return list.stream().map(item -> {
            QuotaRateItemRespVO respVO = BeanUtils.toBean(item, QuotaRateItemRespVO.class);
            respVO.setFields(rateFieldService.getRateFieldList(item.getId()));
            respVO.setHasChildren(rateItemMapper.hasChildren(item.getId()));
            return respVO;
        }).collect(Collectors.toList());
    }

    @Override
    public List<QuotaRateItemRespVO> getRateItemTree(Long catalogItemId) {
        // 1. 查询所有费率项
        List<QuotaRateItemDO> allItems = rateItemMapper.selectListByCatalogItemId(catalogItemId);
        if (CollUtil.isEmpty(allItems)) {
            return Collections.emptyList();
        }
        
        // 2. 查询所有字段绑定
        List<Long> itemIds = allItems.stream().map(QuotaRateItemDO::getId).collect(Collectors.toList());
        List<QuotaRateFieldDO> allFields = rateFieldMapper.selectListByRateItemIds(itemIds);
        Map<Long, List<QuotaRateFieldDO>> fieldMap = allFields.stream()
                .collect(Collectors.groupingBy(QuotaRateFieldDO::getRateItemId));
        
        // 3. 转换为 VO
        List<QuotaRateItemRespVO> allVOs = allItems.stream().map(item -> {
            QuotaRateItemRespVO vo = BeanUtils.toBean(item, QuotaRateItemRespVO.class);
            List<QuotaRateFieldDO> fields = fieldMap.get(item.getId());
            if (fields != null) {
                vo.setFields(BeanUtils.toBean(fields, QuotaRateFieldRespVO.class));
            }
            return vo;
        }).collect(Collectors.toList());
        
        // 4. 构建树结构
        return buildTree(allVOs);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        // 1. 查询两个节点
        QuotaRateItemDO node1 = validateRateItemExists(nodeId1);
        QuotaRateItemDO node2 = validateRateItemExists(nodeId2);
        
        // 2. 验证同级（parent_id 相同）
        if (!Objects.equals(node1.getParentId(), node2.getParentId())) {
            throw exception(QUOTA_RATE_ITEM_NOT_SAME_LEVEL);
        }
        
        // 3. 验证同一模式（catalog_item_id 相同）
        if (!Objects.equals(node1.getCatalogItemId(), node2.getCatalogItemId())) {
            throw exception(QUOTA_RATE_ITEM_NOT_SAME_MODE);
        }
        
        // 4. 交换排序值
        Integer temp = node1.getSortOrder();
        rateItemMapper.updateSortOrder(nodeId1, node2.getSortOrder());
        rateItemMapper.updateSortOrder(nodeId2, temp);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void configValueRules(QuotaRateValueRulesReqVO reqVO) {
        // 1. 验证费率项存在
        QuotaRateItemDO rateItem = validateRateItemExists(reqVO.getRateItemId());
        
        // 2. 验证是数值节点
        if (!rateItem.isValue()) {
            throw exception(QUOTA_RATE_ITEM_NOT_VALUE_NODE);
        }
        
        // 3. 构建规则
        Map<String, Object> settings = rateItem.getSettings();
        if (settings == null) {
            settings = new HashMap<>();
        }
        
        Map<String, Object> valueRules = new HashMap<>();
        if (reqVO.getTiers() != null) {
            valueRules.put("tiers", reqVO.getTiers());
        }
        if (reqVO.getIncrements() != null) {
            valueRules.put("increments", reqVO.getIncrements());
        }
        settings.put("valueRules", valueRules);
        
        // 4. 更新
        rateItem.setSettings(settings);
        rateItem.setValueMode(QuotaRateItemDO.VALUE_MODE_DYNAMIC);
        rateItemMapper.updateById(rateItem);
    }

    @Override
    @SuppressWarnings("unchecked")
    public Map<Integer, BigDecimal> calculateDynamicFields(Long rateItemId, BigDecimal baseValue) {
        QuotaRateItemDO rateItem = validateRateItemExists(rateItemId);
        
        if (!rateItem.isDynamicMode()) {
            return Collections.emptyMap();
        }
        
        Map<String, Object> valueRules = rateItem.getValueRules();
        if (valueRules == null) {
            return Collections.emptyMap();
        }
        
        Map<Integer, BigDecimal> result = new HashMap<>();
        
        // 1. 获取阶梯规则
        List<Map<String, Object>> tiers = (List<Map<String, Object>>) valueRules.get("tiers");
        if (tiers == null || tiers.isEmpty()) {
            return result;
        }
        
        // 2. 按阈值排序
        tiers.sort(Comparator.comparing(t -> new BigDecimal(t.get("threshold").toString())));
        
        // 3. 找到匹配的阶梯
        Map<String, Object> matchedTier = null;
        for (Map<String, Object> tier : tiers) {
            BigDecimal threshold = new BigDecimal(tier.get("threshold").toString());
            String compareType = (String) tier.getOrDefault("compareType", "lte");
            
            boolean matched = false;
            switch (compareType) {
                case "lte":
                    matched = baseValue.compareTo(threshold) <= 0;
                    break;
                case "lt":
                    matched = baseValue.compareTo(threshold) < 0;
                    break;
                case "gte":
                    matched = baseValue.compareTo(threshold) >= 0;
                    break;
                case "gt":
                    matched = baseValue.compareTo(threshold) > 0;
                    break;
            }
            
            if (matched) {
                matchedTier = tier;
                break;
            }
        }
        
        // 4. 如果没有匹配，使用最后一个阶梯
        if (matchedTier == null && !tiers.isEmpty()) {
            matchedTier = tiers.get(tiers.size() - 1);
        }
        
        // 5. 获取基础字段值
        if (matchedTier != null) {
            Map<String, Object> fieldValues = (Map<String, Object>) matchedTier.get("fieldValues");
            if (fieldValues != null) {
                for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
                    Integer fieldIndex = Integer.parseInt(entry.getKey());
                    BigDecimal value = new BigDecimal(entry.getValue().toString());
                    result.put(fieldIndex, value);
                }
            }
        }
        
        // 6. 计算增量
        List<Map<String, Object>> increments = (List<Map<String, Object>>) valueRules.get("increments");
        if (increments != null && !increments.isEmpty()) {
            for (Map<String, Object> increment : increments) {
                BigDecimal step = new BigDecimal(increment.get("step").toString());
                BigDecimal baseThreshold = increment.get("baseThreshold") != null 
                        ? new BigDecimal(increment.get("baseThreshold").toString()) 
                        : BigDecimal.ZERO;
                
                // 计算超出部分
                if (baseValue.compareTo(baseThreshold) > 0) {
                    BigDecimal excess = baseValue.subtract(baseThreshold);
                    BigDecimal times = excess.divide(step, 10, RoundingMode.HALF_UP);
                    
                    Map<String, Object> fieldIncrements = (Map<String, Object>) increment.get("fieldIncrements");
                    if (fieldIncrements != null) {
                        for (Map.Entry<String, Object> entry : fieldIncrements.entrySet()) {
                            Integer fieldIndex = Integer.parseInt(entry.getKey());
                            BigDecimal incrementValue = new BigDecimal(entry.getValue().toString());
                            BigDecimal addValue = incrementValue.multiply(times);
                            
                            result.merge(fieldIndex, addValue, BigDecimal::add);
                        }
                    }
                }
            }
        }
        
        return result;
    }

    @Override
    public QuotaRateItemDO validateRateItemExists(Long id) {
        QuotaRateItemDO rateItem = rateItemMapper.selectById(id);
        if (rateItem == null) {
            throw exception(QUOTA_RATE_ITEM_NOT_EXISTS);
        }
        return rateItem;
    }

    // ==================== 私有方法 ====================

    /**
     * 验证模式节点
     */
    private void validateRateModeNode(Long catalogItemId) {
        QuotaCatalogItemDO catalogItem = catalogItemMapper.selectById(catalogItemId);
        if (catalogItem == null) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS);
        }
        
        // 验证是否为 rate_mode 节点
        Map<String, Object> attributes = catalogItem.getAttributes();
        if (attributes == null || !"rate_mode".equals(attributes.get("node_type"))) {
            throw exception(QUOTA_RATE_ITEM_CATALOG_NOT_RATE_MODE);
        }
    }

    private void validateParent(Long parentId, Long catalogItemId) {
        if (parentId == null) {
            return;
        }
        QuotaRateItemDO parent = rateItemMapper.selectById(parentId);
        if (parent == null) {
            throw exception(QUOTA_RATE_ITEM_PARENT_NOT_EXISTS);
        }
        if (!Objects.equals(parent.getCatalogItemId(), catalogItemId)) {
            throw exception(QUOTA_RATE_ITEM_PARENT_NOT_SAME_MODE);
        }
        if (!parent.isDirectory()) {
            throw exception(QUOTA_RATE_ITEM_PARENT_NOT_DIRECTORY);
        }
    }

    private Integer calculateLevel(Long parentId) {
        if (parentId == null) {
            return 1;
        }
        QuotaRateItemDO parent = rateItemMapper.selectById(parentId);
        return parent == null ? 1 : parent.getLevel() + 1;
    }

    private List<QuotaRateItemRespVO> buildTree(List<QuotaRateItemRespVO> allVOs) {
        Map<Long, QuotaRateItemRespVO> voMap = allVOs.stream()
                .collect(Collectors.toMap(QuotaRateItemRespVO::getId, v -> v));
        
        List<QuotaRateItemRespVO> roots = new ArrayList<>();
        
        for (QuotaRateItemRespVO vo : allVOs) {
            if (vo.getParentId() == null) {
                roots.add(vo);
            } else {
                QuotaRateItemRespVO parent = voMap.get(vo.getParentId());
                if (parent != null) {
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>());
                    }
                    parent.getChildren().add(vo);
                }
            }
        }
        
        // 设置 hasChildren
        for (QuotaRateItemRespVO vo : allVOs) {
            vo.setHasChildren(vo.getChildren() != null && !vo.getChildren().isEmpty());
        }
        
        return roots;
    }
}
