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

import com.yhy.module.core.dal.dataobject.workbench.WbBoqDivisionDO;
import com.yhy.module.core.dal.mysql.workbench.WbBoqDivisionMapper;
import com.yhy.module.core.service.workbench.QuotaQtyFormulaService;
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.regex.Pattern;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

/**
 * 定额工程量公式计算服务实现
 * 
 * @author yhy
 */
@Service
@Slf4j
public class QuotaQtyFormulaServiceImpl implements QuotaQtyFormulaService {

    /**
     * 公式合法性正则：只允许 QDL、数字、+-* /()、空格、小数点
     */
    private static final Pattern FORMULA_PATTERN = Pattern.compile("^[QDL0-9+\\-*/().\\s]+$");

    /**
     * 工程量小数位数
     */
    private static final int QTY_SCALE = 3;

    @Resource
    private WbBoqDivisionMapper wbBoqDivisionMapper;

    @Override
    public FormulaValidationResult validateFormula(String formula) {
        if (!StringUtils.hasText(formula)) {
            return FormulaValidationResult.failure("公式不能为空");
        }

        String trimmedFormula = formula.trim();

        // 检查公式格式
        if (!FORMULA_PATTERN.matcher(trimmedFormula).matches()) {
            return FormulaValidationResult.failure("公式格式不正确，只允许使用 QDL、数字和运算符(+-*/)");
        }

        // 尝试用测试值计算
        try {
            BigDecimal testResult = calculateQuotaQty(trimmedFormula, BigDecimal.valueOf(100));
            return FormulaValidationResult.success(testResult);
        } catch (Exception e) {
            return FormulaValidationResult.failure("公式计算失败: " + e.getMessage());
        }
    }

    @Override
    public BigDecimal calculateQuotaQty(String formula, BigDecimal qdlValue) {
        return calculateQuotaQty(formula, qdlValue, null);
    }

    @Override
    public BigDecimal calculateQuotaQty(String formula, BigDecimal qdlValue, String quotaUnit) {
        if (!StringUtils.hasText(formula)) {
            return BigDecimal.ZERO;
        }

        String trimmedFormula = formula.trim();

        // 解析单位换算系数（提前解析，纯数字也需要换算）
        BigDecimal unitFactor = parseUnitFactor(quotaUnit);

        // 如果公式是纯数字，进行单位换算后返回
        // 例如：输入9，单位100m，结果为 9/100 = 0.090
        try {
            BigDecimal directValue = new BigDecimal(trimmedFormula);
            // 单位带数值时，需要除以换算系数
            if (unitFactor.compareTo(BigDecimal.ONE) != 0 && unitFactor.compareTo(BigDecimal.ZERO) != 0) {
                directValue = directValue.divide(unitFactor, QTY_SCALE, RoundingMode.HALF_UP);
            }
            return directValue.setScale(QTY_SCALE, RoundingMode.HALF_UP);
        } catch (NumberFormatException ignored) {
            // 不是纯数字，继续解析公式
        }
        
        // QDL 使用原始清单工程量（不预先换算）
        BigDecimal originalQdlValue = qdlValue != null ? qdlValue : BigDecimal.ZERO;

        // 如果公式只是 QDL，直接返回换算后的工程量
        if ("QDL".equalsIgnoreCase(trimmedFormula)) {
            // 单位带数值时，结果 = 清单工程量 / 单位系数
            if (unitFactor.compareTo(BigDecimal.ONE) != 0 && unitFactor.compareTo(BigDecimal.ZERO) != 0) {
                return originalQdlValue.divide(unitFactor, QTY_SCALE, RoundingMode.HALF_UP);
            }
            return originalQdlValue.setScale(QTY_SCALE, RoundingMode.HALF_UP);
        }

        // 替换 QDL 变量并计算（使用原始清单工程量）
        Map<String, BigDecimal> variables = new HashMap<>();
        variables.put("QDL", originalQdlValue);

        BigDecimal result = FormulaEvaluator.evaluate(trimmedFormula, variables);
        
        // 公式计算完成后，再进行单位换算
        // 例如：QDL*(20+95)+6 = 9*115+6 = 1041，然后 1041/100 = 10.41
        if (unitFactor.compareTo(BigDecimal.ONE) != 0 && unitFactor.compareTo(BigDecimal.ZERO) != 0) {
            result = result.divide(unitFactor, QTY_SCALE, RoundingMode.HALF_UP);
        }
        return result.setScale(QTY_SCALE, RoundingMode.HALF_UP);
    }

    @Override
    public BigDecimal parseUnitFactor(String unit) {
        if (!StringUtils.hasText(unit)) {
            return BigDecimal.ONE;
        }

        String trimmedUnit = unit.trim();
        
        // 使用正则匹配单位开头的数字（支持整数和小数）
        java.util.regex.Matcher matcher = Pattern.compile("^(\\d+\\.?\\d*)").matcher(trimmedUnit);
        if (matcher.find()) {
            try {
                return new BigDecimal(matcher.group(1));
            } catch (NumberFormatException e) {
                log.warn("解析单位系数失败: {}", unit);
                return BigDecimal.ONE;
            }
        }
        
        // 没有数字前缀，返回1（不换算）
        return BigDecimal.ONE;
    }

    @Override
    public BigDecimal recalculateQuotaQty(Long quotaDivisionId) {
        WbBoqDivisionDO quota = wbBoqDivisionMapper.selectById(quotaDivisionId);
        if (quota == null) {
            log.warn("定额节点不存在: {}", quotaDivisionId);
            return BigDecimal.ZERO;
        }

        if (!WbBoqDivisionDO.NODE_TYPE_QUOTA.equals(quota.getNodeType())) {
            log.warn("节点不是定额类型: {}", quotaDivisionId);
            return quota.getQty();
        }

        // 获取父清单的工程量
        BigDecimal qdlValue = getParentBoqQty(quota.getParentId());

        // 计算定额工程量
        String formula = quota.getQuotaQtyFormula();
        if (!StringUtils.hasText(formula)) {
            // 没有公式，保持原值
            return quota.getQty();
        }

        // 带单位换算计算工程量
        BigDecimal newQty = calculateQuotaQty(formula, qdlValue, quota.getUnit());

        // 更新数据库
        WbBoqDivisionDO updateDO = new WbBoqDivisionDO();
        updateDO.setId(quotaDivisionId);
        updateDO.setQty(newQty);
        wbBoqDivisionMapper.updateById(updateDO);

        return newQty;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recalculateChildQuotaQty(Long boqDivisionId) {
        WbBoqDivisionDO boq = wbBoqDivisionMapper.selectById(boqDivisionId);
        if (boq == null) {
            log.warn("清单节点不存在: {}", boqDivisionId);
            return;
        }

        if (!WbBoqDivisionDO.NODE_TYPE_BOQ.equals(boq.getNodeType())) {
            log.warn("节点不是清单类型: {}", boqDivisionId);
            return;
        }

        BigDecimal qdlValue = boq.getQty();

        // 查询所有子定额
        List<WbBoqDivisionDO> quotas = wbBoqDivisionMapper.selectList(
            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<WbBoqDivisionDO>()
                .eq(WbBoqDivisionDO::getParentId, boqDivisionId)
                .eq(WbBoqDivisionDO::getNodeType, WbBoqDivisionDO.NODE_TYPE_QUOTA)
        );

        for (WbBoqDivisionDO quota : quotas) {
            String formula = quota.getQuotaQtyFormula();
            if (!StringUtils.hasText(formula)) {
                continue;
            }

            // 带单位换算计算工程量
            BigDecimal newQty = calculateQuotaQty(formula, qdlValue, quota.getUnit());

            // 只有值变化时才更新
            if (quota.getQty() == null || quota.getQty().compareTo(newQty) != 0) {
                WbBoqDivisionDO updateDO = new WbBoqDivisionDO();
                updateDO.setId(quota.getId());
                updateDO.setQty(newQty);
                wbBoqDivisionMapper.updateById(updateDO);
                log.debug("更新定额工程量: {} -> {}", quota.getId(), newQty);
            }
        }
    }

    /**
     * 获取父清单的工程量
     */
    private BigDecimal getParentBoqQty(Long parentId) {
        if (parentId == null) {
            return BigDecimal.ZERO;
        }

        WbBoqDivisionDO parent = wbBoqDivisionMapper.selectById(parentId);
        if (parent == null) {
            return BigDecimal.ZERO;
        }

        // 如果父节点是清单，返回其工程量
        if (WbBoqDivisionDO.NODE_TYPE_BOQ.equals(parent.getNodeType())) {
            return parent.getQty() != null ? parent.getQty() : BigDecimal.ZERO;
        }

        // 如果父节点不是清单，继续向上查找
        return getParentBoqQty(parent.getParentId());
    }
}
