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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import com.yhy.module.core.controller.admin.quota.vo.QuotaFeeItemSaveReqVO;
import com.yhy.module.core.dal.dataobject.quota.QuotaCatalogItemDO;
import com.yhy.module.core.dal.dataobject.quota.QuotaFeeItemDO;
import com.yhy.module.core.dal.mysql.quota.QuotaCatalogItemMapper;
import com.yhy.module.core.dal.mysql.quota.QuotaFeeItemMapper;
import com.yhy.module.core.service.quota.QuotaFeeItemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Set;

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

/**
 * 定额取费项 Service 实现类
 */
@Service
@Validated
@Slf4j
public class QuotaFeeItemServiceImpl implements QuotaFeeItemService {

    @Resource
    private QuotaFeeItemMapper quotaFeeItemMapper;

    @Resource
    private QuotaCatalogItemMapper quotaCatalogItemMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createFeeItem(QuotaFeeItemSaveReqVO createReqVO) {
        // 1. 验证模式节点
        validateRateModeNode(createReqVO.getCatalogItemId());

        // 2. 验证计算基数
        if (createReqVO.getCalcBase() != null) {
            validateCalcBase(createReqVO.getCalcBase());
        }

        // 3. 验证自定义序号唯一性
        if (StrUtil.isNotBlank(createReqVO.getCustomCode())) {
            validateCustomCodeUnique(null, createReqVO.getCatalogItemId(), createReqVO.getCustomCode());
        }

        // 4. 设置排序值
        if (createReqVO.getSortOrder() == null) {
            Integer maxSortOrder = quotaFeeItemMapper.selectMaxSortOrder(createReqVO.getCatalogItemId());
            createReqVO.setSortOrder(maxSortOrder + 1);
        }

        // 5. 插入数据
        QuotaFeeItemDO feeItem = BeanUtils.toBean(createReqVO, QuotaFeeItemDO.class);
        quotaFeeItemMapper.insert(feeItem);

        return feeItem.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateFeeItem(QuotaFeeItemSaveReqVO updateReqVO) {
        // 1. 验证存在
        validateFeeItemExists(updateReqVO.getId());

        // 2. 验证模式节点
        validateRateModeNode(updateReqVO.getCatalogItemId());

        // 3. 验证计算基数
        if (updateReqVO.getCalcBase() != null) {
            validateCalcBase(updateReqVO.getCalcBase());
        }

        // 4. 验证自定义序号唯一性
        if (StrUtil.isNotBlank(updateReqVO.getCustomCode())) {
            validateCustomCodeUnique(updateReqVO.getId(), updateReqVO.getCatalogItemId(), updateReqVO.getCustomCode());
        }

        // 5. 更新数据
        QuotaFeeItemDO updateObj = BeanUtils.toBean(updateReqVO, QuotaFeeItemDO.class);
        quotaFeeItemMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFeeItem(Long id) {
        // 1. 验证存在
        validateFeeItemExists(id);

        // 2. 删除
        quotaFeeItemMapper.deleteById(id);
    }

    @Override
    public QuotaFeeItemDO getFeeItem(Long id) {
        return quotaFeeItemMapper.selectById(id);
    }

    @Override
    public List<QuotaFeeItemDO> getFeeItemList(Long catalogItemId) {
        return quotaFeeItemMapper.selectListByCatalogItemId(catalogItemId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void swapSort(Long nodeId1, Long nodeId2) {
        // 1. 查询两个节点（使用行锁）
        QuotaFeeItemDO node1 = quotaFeeItemMapper.selectById(nodeId1);
        QuotaFeeItemDO node2 = quotaFeeItemMapper.selectById(nodeId2);

        if (node1 == null || node2 == null) {
            throw exception(QUOTA_FEE_ITEM_NOT_EXISTS);
        }

        // 2. 验证是否在同一模式下
        if (!node1.getCatalogItemId().equals(node2.getCatalogItemId())) {
            throw exception(QUOTA_FEE_ITEM_NOT_SAME_CATALOG);
        }

        // 3. 交换排序值
        Integer tempSort = node1.getSortOrder();
        node1.setSortOrder(node2.getSortOrder());
        node2.setSortOrder(tempSort);

        // 4. 更新数据库
        quotaFeeItemMapper.updateById(node1);
        quotaFeeItemMapper.updateById(node2);
    }

    @Override
    public void validateFeeItemExists(Long id) {
        if (quotaFeeItemMapper.selectById(id) == null) {
            throw exception(QUOTA_FEE_ITEM_NOT_EXISTS);
        }
    }

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

    /**
     * 验证模式节点
     */
    private void validateRateModeNode(Long catalogItemId) {
        QuotaCatalogItemDO catalogItem = quotaCatalogItemMapper.selectById(catalogItemId);
        if (catalogItem == null) {
            throw exception(QUOTA_CATALOG_ITEM_NOT_EXISTS);
        }

        // 验证 node_type 必须是 rate_mode
        Map<String, Object> attributes = catalogItem.getAttributes();
        if (attributes == null || !"rate_mode".equals(attributes.get("node_type"))) {
            throw exception(QUOTA_FEE_ITEM_CATALOG_NOT_RATE_MODE);
        }
    }

    /**
     * 验证计算基数
     */
    private void validateCalcBase(Map<String, Object> calcBase) {
        // 1. 验证必填字段
        String formula = (String) calcBase.get("formula");
        if (StrUtil.isBlank(formula)) {
            throw exception(QUOTA_FEE_CALC_BASE_FORMULA_EMPTY);
        }

        @SuppressWarnings("unchecked")
        Map<String, String> variables = (Map<String, String>) calcBase.get("variables");
        if (MapUtil.isEmpty(variables)) {
            throw exception(QUOTA_FEE_CALC_BASE_VARIABLES_EMPTY);
        }

        // 2. 验证价格代码必须是固定的4个值
        Set<String> allowedCodes = CollUtil.newHashSet(
                QuotaFeeItemDO.PRICE_CODE_TAX_EXCL_BASE,
                QuotaFeeItemDO.PRICE_CODE_TAX_INCL_BASE,
                QuotaFeeItemDO.PRICE_CODE_TAX_EXCL_COMPILE,
                QuotaFeeItemDO.PRICE_CODE_TAX_INCL_COMPILE
        );

        for (String priceCode : variables.values()) {
            if (!allowedCodes.contains(priceCode)) {
                throw exception(QUOTA_FEE_CALC_BASE_INVALID_PRICE_CODE, priceCode);
            }
        }

        // 3. 验证公式语法
        validateFormulaSyntax(formula, variables.keySet());
    }

    /**
     * 验证公式语法
     */
    private void validateFormulaSyntax(String formula, Set<String> variableNames) {
        // 1. 验证括号匹配
        int leftCount = 0;
        int rightCount = 0;
        for (char c : formula.toCharArray()) {
            if (c == '(') leftCount++;
            if (c == ')') rightCount++;
        }
        if (leftCount != rightCount) {
            throw exception(QUOTA_FEE_CALC_BASE_FORMULA_BRACKET_MISMATCH);
        }

        // 2. 验证只包含允许的字符（数字、运算符、括号、空格、中文）
        String allowedPattern = "[0-9+\\-*/()\\s\\u4e00-\\u9fa5]+";
        if (!formula.matches(allowedPattern)) {
            throw exception(QUOTA_FEE_CALC_BASE_FORMULA_INVALID_CHAR);
        }

        // 3. 验证公式中使用的变量都在 variables 中定义
        for (String varName : variableNames) {
            if (!formula.contains(varName)) {
                log.warn("公式中未使用变量: {}", varName);
            }
        }
    }

    /**
     * 验证自定义序号唯一性
     */
    private void validateCustomCodeUnique(Long id, Long catalogItemId, String customCode) {
        QuotaFeeItemDO existingItem = quotaFeeItemMapper.selectByCustomCode(catalogItemId, customCode);
        if (existingItem != null && !existingItem.getId().equals(id)) {
            throw exception(QUOTA_FEE_ITEM_CUSTOM_CODE_DUPLICATE, customCode);
        }
    }
}
