package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.vpp.domain.VppResponseDeviationPrice;
import com.usky.vpp.mapper.VppResponseDeviationPriceMapper;
import com.usky.vpp.service.VppResponseDeviationPriceService;
import com.usky.vpp.service.vo.ResponseDeviationPriceAdjustmentRequest;
import com.usky.vpp.service.vo.ResponseDeviationPriceAdjustmentVO;
import com.usky.vpp.util.VppAuditHelper;
import com.usky.vpp.util.VppPageHelper;
import com.usky.vpp.util.VppResponseCoefficientHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 响应量偏差价格调整配置服务实现。
 */
@Service
public class VppResponseDeviationPriceServiceImpl implements VppResponseDeviationPriceService {

    @Autowired
    private VppResponseDeviationPriceMapper adjustmentMapper;

    @Override
    public CommonPage<ResponseDeviationPriceAdjustmentVO> page(BigDecimal completionRate,
                                                                Integer current,
                                                                Integer size) {
        Map<String, Object> pageParams = new HashMap<>(2);
        pageParams.put("current", current);
        pageParams.put("size", size);
        Page<VppResponseDeviationPrice> page = VppPageHelper.of(pageParams);

        LambdaQueryWrapper<VppResponseDeviationPrice> wrapper =
                new LambdaQueryWrapper<VppResponseDeviationPrice>()
                        .eq(VppResponseDeviationPrice::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                        .orderByAsc(VppResponseDeviationPrice::getId);
        applyTenantFilter(wrapper);
        if (completionRate != null) {
            applyCompletionRateFilter(wrapper, completionRate);
        }

        Page<VppResponseDeviationPrice> result = adjustmentMapper.selectPage(page, wrapper);
        List<ResponseDeviationPriceAdjustmentVO> records = result.getRecords().stream()
                .map(this::toVo)
                .collect(Collectors.toList());
        return new CommonPage<>(records, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public ResponseDeviationPriceAdjustmentVO get(Long id) {
        return toVo(requireAdjustment(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(ResponseDeviationPriceAdjustmentRequest request) {
        validateRequest(request, null);
        VppResponseDeviationPrice adjustment = new VppResponseDeviationPrice();
        fillFromRequest(adjustment, request);
        VppAuditHelper.fillCreate(adjustment);
        adjustmentMapper.insert(adjustment);
        return adjustment.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, ResponseDeviationPriceAdjustmentRequest request) {
        VppResponseDeviationPrice adjustment = requireAdjustment(id);
        validateRequest(request, id);
        fillFromRequest(adjustment, request);
        VppAuditHelper.fillUpdate(adjustment);
        adjustmentMapper.updateById(adjustment);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        VppResponseDeviationPrice adjustment = requireAdjustment(id);
        VppAuditHelper.fillSoftDelete(adjustment);
        adjustmentMapper.updateById(adjustment);
    }

    private VppResponseDeviationPrice requireAdjustment(Long id) {
        if (id == null) {
            throw new BusinessException("主键ID不能为空");
        }
        VppResponseDeviationPrice adjustment = adjustmentMapper.selectById(id);
        if (adjustment == null || VppAuditHelper.isDeleted(adjustment.getDeleteFlag())) {
            throw new BusinessException("响应量偏差价格调整配置不存在");
        }
        Integer tenantId = SecurityUtils.getTenantId();
        if (tenantId != null && adjustment.getTenantId() != null
                && !tenantId.equals(adjustment.getTenantId())) {
            throw new BusinessException("响应量偏差价格调整配置不存在");
        }
        return adjustment;
    }

    private void fillFromRequest(VppResponseDeviationPrice adjustment,
                                 ResponseDeviationPriceAdjustmentRequest request) {
        VppResponseCoefficientHelper.Range range = toRange(request);
        adjustment.setCoeffLower(range.getLower());
        adjustment.setCoeffUpper(range.getUpper());
        adjustment.setLowerInclusive(range.isLowerInclusive());
        adjustment.setUpperInclusive(range.isUpperInclusive());
        adjustment.setPriceAdjustmentCoefficient(request.getPriceAdjustmentCoefficient());
        adjustment.setRemark(request.getRemark());
    }

    private void validateRequest(ResponseDeviationPriceAdjustmentRequest request, Long excludeId) {
        if (request == null) {
            throw new BusinessException("请求体不能为空");
        }
        VppResponseCoefficientHelper.Range requestRange = toRange(request);
        if (request.getPriceAdjustmentCoefficient() == null) {
            throw new BusinessException("价格调整系数不能为空");
        }
        if (request.getPriceAdjustmentCoefficient().compareTo(BigDecimal.ZERO) < 0) {
            throw new BusinessException("价格调整系数不能小于0");
        }

        Integer tenantId = SecurityUtils.getTenantId();
        List<VppResponseDeviationPrice> existing = adjustmentMapper.selectList(
                new LambdaQueryWrapper<VppResponseDeviationPrice>()
                        .eq(VppResponseDeviationPrice::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                        .eq(tenantId != null, VppResponseDeviationPrice::getTenantId, tenantId)
                        .ne(excludeId != null, VppResponseDeviationPrice::getId, excludeId));
        for (VppResponseDeviationPrice item : existing) {
            VppResponseCoefficientHelper.Range existingRange = toRange(item);
            if (VppResponseCoefficientHelper.overlaps(requestRange, existingRange)) {
                throw new BusinessException("响应量系数区间与已有配置重叠："
                        + VppResponseCoefficientHelper.format(existingRange));
            }
        }
    }

    private VppResponseCoefficientHelper.Range toRange(ResponseDeviationPriceAdjustmentRequest request) {
        return VppResponseCoefficientHelper.of(
                request.getCoeffLower(),
                request.getCoeffUpper(),
                request.getLowerInclusive(),
                request.getUpperInclusive());
    }

    private VppResponseCoefficientHelper.Range toRange(VppResponseDeviationPrice adjustment) {
        return VppResponseCoefficientHelper.of(
                adjustment.getCoeffLower(),
                adjustment.getCoeffUpper(),
                adjustment.getLowerInclusive(),
                adjustment.getUpperInclusive());
    }

    /**
     * SQL 层按完成率匹配结构化区间。
     */
    private void applyCompletionRateFilter(LambdaQueryWrapper<VppResponseDeviationPrice> wrapper,
                                           BigDecimal completionRate) {
        wrapper.apply(
                "(coeff_lower IS NULL OR "
                        + "(lower_inclusive = 1 AND {0} >= coeff_lower) OR "
                        + "(lower_inclusive = 0 AND {0} > coeff_lower))"
                        + " AND "
                        + "(coeff_upper IS NULL OR "
                        + "(upper_inclusive = 1 AND {0} <= coeff_upper) OR "
                        + "(upper_inclusive = 0 AND {0} < coeff_upper))",
                completionRate);
    }

    private ResponseDeviationPriceAdjustmentVO toVo(VppResponseDeviationPrice adjustment) {
        ResponseDeviationPriceAdjustmentVO vo = new ResponseDeviationPriceAdjustmentVO();
        vo.setId(adjustment.getId());
        vo.setCoeffLower(adjustment.getCoeffLower());
        vo.setCoeffUpper(adjustment.getCoeffUpper());
        vo.setLowerInclusive(Boolean.TRUE.equals(adjustment.getLowerInclusive()));
        vo.setUpperInclusive(Boolean.TRUE.equals(adjustment.getUpperInclusive()));
        vo.setResponseCoefficientLabel(VppResponseCoefficientHelper.format(
                adjustment.getCoeffLower(),
                adjustment.getCoeffUpper(),
                adjustment.getLowerInclusive(),
                adjustment.getUpperInclusive()));
        vo.setPriceAdjustmentCoefficient(adjustment.getPriceAdjustmentCoefficient());
        vo.setRemark(adjustment.getRemark());
        vo.setCreateTime(adjustment.getCreateTime());
        vo.setUpdateTime(adjustment.getUpdateTime());
        return vo;
    }

    private void applyTenantFilter(LambdaQueryWrapper<VppResponseDeviationPrice> wrapper) {
        Integer tenantId = SecurityUtils.getTenantId();
        if (tenantId != null) {
            wrapper.eq(VppResponseDeviationPrice::getTenantId, tenantId);
        }
    }
}
