package com.ylx.order.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DateUtils;
import com.ylx.common.utils.SecurityUtils;
import com.ylx.order.domain.RefundRuleDetail;
import com.ylx.order.domain.RefundRuleMaster;
import com.ylx.order.domain.dto.RegulationConfigDTO;
import com.ylx.order.enums.RefundStageTypeEnum;
import com.ylx.order.mapper.RefundRuleMasterMapper;
import com.ylx.order.service.RefundRuleDetailService;
import com.ylx.order.service.RefundRuleMasterService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
public class RefundRuleMasterServiceImpl extends ServiceImpl<RefundRuleMasterMapper, RefundRuleMaster> implements RefundRuleMasterService {

    @Resource
    private RefundRuleDetailService refundRuleDetailService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleRefundRules(RegulationConfigDTO dto) {

        String operator = SecurityUtils.getUsername();
        // 第一步：处理 MASTER 表
        Long preDepartureMasterId = createOrUpdateMaster(RefundStageTypeEnum.PRE_DEPARTURE.getCode(), operator);
        Long onWayMasterId = createOrUpdateMaster(RefundStageTypeEnum.ON_THE_WAY.getCode(), operator);
        Long inServiceMasterId = createOrUpdateMaster(RefundStageTypeEnum.IN_SERVICE.getCode(), operator);

        // 第二步：清理旧的 DETAIL 数据
        clearDetailsByStage(RefundStageTypeEnum.PRE_DEPARTURE.getCode(), operator);
        clearDetailsByStage(RefundStageTypeEnum.ON_THE_WAY.getCode(), operator);
        clearDetailsByStage(RefundStageTypeEnum.IN_SERVICE.getCode(), operator);

        // 第三步：组装并插入新的 DETAIL 数据
        List<RefundRuleDetail> allDetails = new ArrayList<>();

        // 1. 处理【商户未出发前】逻辑 (最复杂的部分)
        handlePreDepartureDetails(preDepartureMasterId, dto.getPreDepartureStrategy(), dto.getPreDepartureRules(), allDetails, operator);

        // 2. 处理【商户已出发】逻辑
        handleSimpleStageDetails(onWayMasterId, dto.getOnWayRules(), RefundStageTypeEnum.ON_THE_WAY.getCode(), allDetails, operator);

        // 3. 处理【服务进行中】逻辑
        handleSimpleStageDetails(inServiceMasterId, dto.getInServiceRules(), RefundStageTypeEnum.IN_SERVICE.getCode(), allDetails, operator);

        // 批量插入明细
        if (!allDetails.isEmpty()) {
            this.refundRuleDetailService.saveBatch(allDetails);
            log.info("成功保存退款规则明细，共 {} 条", allDetails.size());
        }
    }

    @Override
    public void loadRefundRules(RegulationConfigDTO dto) {
        loadPreDepartureRules(dto);
        dto.setOnWayRules(loadSimpleStageRules(RefundStageTypeEnum.ON_THE_WAY.getCode()));
        dto.setInServiceRules(loadSimpleStageRules(RefundStageTypeEnum.IN_SERVICE.getCode()));
    }

    private void loadPreDepartureRules(RegulationConfigDTO dto) {
        List<RefundRuleDetail> details = listDetailsByStage(RefundStageTypeEnum.PRE_DEPARTURE.getCode());

        if (CollUtil.isEmpty(details)) {
            dto.setPreDepartureStrategy(0);
            dto.setPreDepartureRules(Collections.emptyList());
            return;
        }

        RefundRuleDetail first = CollUtil.getFirst(details);
        if (details.size() == 1 && ObjectUtil.equals(0, first.getRefundType())) {
            dto.setPreDepartureStrategy(0);
            dto.setPreDepartureRules(Collections.emptyList());
            return;
        }

        dto.setPreDepartureStrategy(1);
        dto.setPreDepartureRules(details.stream().map(this::toTimeRangeRuleItem).collect(Collectors.toList()));
    }

    private List<RegulationConfigDTO.SimplePercentRuleItem> loadSimpleStageRules(Integer stageType) {
        List<RefundRuleDetail> details = listDetailsByStage(stageType);
        if (CollUtil.isEmpty(details)) {
            return Collections.emptyList();
        }

        List<RegulationConfigDTO.SimplePercentRuleItem> rules = new ArrayList<>(1);
        rules.add(toSimplePercentRuleItem(CollUtil.getFirst(details)));
        return rules;
    }

    private List<RefundRuleDetail> listDetailsByStage(Integer stageType) {
        LambdaQueryWrapper<RefundRuleDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RefundRuleDetail::getStageType, stageType)
                .eq(RefundRuleDetail::getIsDelete, 0)
                .orderByAsc(RefundRuleDetail::getSortOrder)
                .orderByAsc(RefundRuleDetail::getId);
        return this.refundRuleDetailService.list(wrapper);
    }

    private RegulationConfigDTO.TimeRangeRuleItem toTimeRangeRuleItem(RefundRuleDetail detail) {
        RegulationConfigDTO.TimeRangeRuleItem item = new RegulationConfigDTO.TimeRangeRuleItem();
        item.setTimeStartHours(detail.getTimeStartHours());
        item.setTimeEndHours(detail.getTimeEndHours());
        item.setRefundPercent(detail.getRefundPercent());
        item.setSortOrder(detail.getSortOrder());
        return item;
    }

    private RegulationConfigDTO.SimplePercentRuleItem toSimplePercentRuleItem(RefundRuleDetail detail) {
        RegulationConfigDTO.SimplePercentRuleItem item = new RegulationConfigDTO.SimplePercentRuleItem();
        item.setRefundType(detail.getRefundType());
        item.setRefundPercent(detail.getRefundPercent());
        return item;
    }

    /**
     * 创建或更新主表记录
     * 逻辑：查找是否存在该 stage_type 的记录，存在则更新时间，不存在则新增
     *
     * @param stageType 阶段类型
     * @param operator  操作人
     * @return Long 主表ID
     */
    private Long createOrUpdateMaster(Integer stageType, String operator) {

        // 查询是否存在
        LambdaQueryWrapper<RefundRuleMaster> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RefundRuleMaster::getStageType, stageType).eq(RefundRuleMaster::getIsDelete, 0);
        RefundRuleMaster existing = this.baseMapper.selectOne(wrapper);

        if (ObjectUtil.isNotNull(existing)) {
            existing.setUpdateTime(DateUtils.getNowDate());
            existing.setUpdateBy(operator);
            this.baseMapper.updateById(existing);
            return existing.getId();
        } else {
            // 新增
            RefundRuleMaster master = new RefundRuleMaster();
            master.setStageType(stageType);
            master.setCreateBy(operator);
            master.setCreateTime(DateUtils.getNowDate());
            master.setIsDelete(0);
            this.baseMapper.insert(master);
            return master.getId();
        }
    }

    /**
     * 处理“未出发前”的特殊逻辑
     *
     * @param masterId 主表ID
     * @param strategy 策略: 0=全额, 1=部分
     * @param rules    前端传来的时间段列表
     * @param operator
     */
    private void handlePreDepartureDetails(Long masterId, Integer strategy, List<RegulationConfigDTO.TimeRangeRuleItem> rules, List<RefundRuleDetail> targetList, String operator) {
        if (strategy == 0) {
            // === 情况 A：全额退款 ===
            RefundRuleDetail detail = new RefundRuleDetail();
            detail.setMasterId(masterId);
            detail.setStageType(RefundStageTypeEnum.PRE_DEPARTURE.getCode());
            detail.setRefundType(0); // 全额
            detail.setRefundPercent(BigDecimal.valueOf(100));
            detail.setSortOrder(1);
            detail.setRefundDesc("出发前全额退款");
            detail.setCreateBy(operator);
            detail.setCreateTime(DateUtils.getNowDate());
            targetList.add(detail);
        } else if (strategy == 1) {
            // === 情况 B：部分退款（分时段） ===
            if (ObjectUtil.isEmpty(rules)) {
                throw new ServiceException("选择部分退款时，必须配置时间段规则！");
            }
            rules.sort(Comparator.comparing(RegulationConfigDTO.TimeRangeRuleItem::getTimeStartHours));

            for (RegulationConfigDTO.TimeRangeRuleItem rule : rules) {
                RefundRuleDetail detail = new RefundRuleDetail();
                detail.setMasterId(masterId);
                detail.setStageType(RefundStageTypeEnum.PRE_DEPARTURE.getCode());

                // 时间窗口
                detail.setTimeStartHours(rule.getTimeStartHours());
                detail.setTimeEndHours(rule.getTimeEndHours());

                // 退款比例
                detail.setRefundType(1); // 部分
                detail.setRefundPercent(rule.getRefundPercent());
                detail.setSortOrder(rule.getSortOrder());

                // 生成描述 (可选)
                String desc = generatePreDepartureDesc(rule);
                detail.setRefundDesc(desc);

                detail.setCreateBy(operator);
                detail.setCreateTime(DateUtils.getNowDate());
                targetList.add(detail);
            }
        }
    }

    /**
     * 处理简单阶段（已出发、进行中）
     * 逻辑：无论全额还是部分，都只有一条记录
     */
    private void handleSimpleStageDetails(Long masterId, List<RegulationConfigDTO.SimplePercentRuleItem> list, Integer refundStageTypeCode, List<RefundRuleDetail> targetList, String operator) {

        // 1. 通过枚举获取阶段描述，用于日志输出
        RefundStageTypeEnum stageEnum = RefundStageTypeEnum.getByCode(refundStageTypeCode);
        if (ObjectUtil.isNull(stageEnum)) {
            throw new ServiceException("refundStageTypeCode参数有误，查不到对应的类型");
        }
        String stageDesc = stageEnum.getInfo();

        // 2. 打印日志，清晰明了
        log.info("开始处理【{}】阶段的退款规则配置...", stageDesc);

        if (CollUtil.isEmpty(list)) {
            throw new ServiceException("【" + stageDesc + "】的比例规则项不能为空");
        }

        RegulationConfigDTO.SimplePercentRuleItem ruleItem = CollUtil.getFirst(list);

        RefundRuleDetail detail = new RefundRuleDetail();
        detail.setMasterId(masterId);
        detail.setStageType(refundStageTypeCode);

        detail.setRefundType(ruleItem.getRefundType());
        detail.setRefundPercent(ruleItem.getRefundPercent());
        detail.setSortOrder(1);

        detail.setCreateBy(operator);
        detail.setCreateTime(DateUtils.getNowDate());

        Integer type = ruleItem.getRefundType();
        BigDecimal percent = ruleItem.getRefundPercent();

        String desc;
        if (type != null && type == 0) {
            desc = stageDesc + "全额退款";
        } else {
            desc = String.format(stageDesc + "，不再支持全额退款，只退实付金额的%s%%", percent);
        }
        detail.setRefundDesc(desc);

        targetList.add(detail);

        // 3. 处理完成日志
        log.debug("【{}】阶段规则构建完成: Type={}, Percent={}",
                stageDesc, ruleItem.getRefundType(), ruleItem.getRefundPercent());
    }

    private void clearDetailsByStage(Integer stageType, String operator) {
        log.warn("正在清理 stage_type={} 的旧明细数据, operator ={} ", stageType, operator);
        this.refundRuleDetailService.clearDetailsByStage(stageType, operator);
    }

    /**
     * 处理复杂阶段（未出发前）
     * 逻辑：根据时间段列表生成多条明细，并动态生成 refundDesc
     */
    private void handleComplexStageDetails(Long masterId, List<RegulationConfigDTO.TimeRangeRuleItem> list, Integer stageType, List<RefundRuleDetail> targetList) {
        if (CollUtil.isEmpty(list)) {
            throw new ServiceException("未出发阶段的退款规则不能为空");
        }

        // 按开始时间排序，确保生成的文案顺序正确（可选，视前端是否已排好序而定）
        list.sort(Comparator.comparing(RegulationConfigDTO.TimeRangeRuleItem::getTimeStartHours));

        int sortIndex = 1;
        for (RegulationConfigDTO.TimeRangeRuleItem item : list) {
            RefundRuleDetail detail = new RefundRuleDetail();
            detail.setMasterId(masterId);
            detail.setStageType(stageType);
            detail.setRefundType(1); // 1代表部分退款/自定义
            detail.setRefundPercent(item.getRefundPercent());
            detail.setSortOrder(sortIndex++);

            // ================= 核心修改：动态生成描述文案 =================
            String desc = generatePreDepartureDesc(item);
            detail.setRefundDesc(desc);
            // ==========================================================

            targetList.add(detail);
        }
    }

    /**
     * 根据时间段规则项生成对应的中文描述
     *
     * @param item 规则项（包含开始时间、结束时间、比例）
     * @return 格式化后的文案
     */
    private String generatePreDepartureDesc(RegulationConfigDTO.TimeRangeRuleItem item) {
        BigDecimal startHour = item.getTimeStartHours();
        BigDecimal endHour = item.getTimeEndHours();
        BigDecimal percent = item.getRefundPercent();

        // 基础文案模板
        String prefix = "距离服务开始前";
        String middle = "小时申请退款，只退付金额的";
        String suffix = "%";

        // 场景 1：标准的区间（例如：24-48小时）
        // 注意：这里需要判断 startHour 是否有值。
        // 如果业务定义 startHour 为 null 或 0 代表“不足X小时”，则走场景 2
        if (startHour != null && startHour.compareTo(BigDecimal.ZERO) > 0) {
            return String.format("%s%s至%s%s%s%s",
                    prefix,
                    formatNumber(startHour), // 去除小数点后的 .0
                    formatNumber(endHour),
                    middle,
                    formatNumber(percent),
                    suffix
            );
        }
        // 场景 2：兜底区间（例如：不足 24 小时）
        else {
            return String.format("距离服务开始不足%s%s%s%s",
                    formatNumber(endHour),
                    middle,
                    formatNumber(percent),
                    suffix
            );
        }
    }

    /**
     * 辅助方法：格式化数字，如果是整数则去掉小数点（24.0 -> 24）
     */
    private String formatNumber(BigDecimal number) {
        if (number == null) return "";
        return number.stripTrailingZeros().toPlainString();
    }

}
