package com.ylx.fareSetting.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.core.domain.entity.SysDictData;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DictUtils;
import com.ylx.common.utils.DistanceUtil;
import com.ylx.fareSetting.domian.MaProjectFareSetting;
import com.ylx.fareSetting.domian.dto.FareCalculateDTO;
import com.ylx.fareSetting.domian.vo.FareCalculateResultVO;
import com.ylx.fareSetting.mapper.MaProjectFareSettingMapper;
import com.ylx.fareSetting.service.IMaProjectFareSettingService;
import com.ylx.address.domain.TAddress;
import com.ylx.massage.domain.dto.DriverFeeDTO;
import com.ylx.massage.domain.vo.TFareSettingVo;
import com.ylx.address.service.TAddressService;
import com.ylx.massage.service.TFareSettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;


@Slf4j
@Service
public class MaProjectFareSettingServiceImpl extends ServiceImpl<MaProjectFareSettingMapper, MaProjectFareSetting> implements IMaProjectFareSettingService {

    @Resource
    private TFareSettingService fareSettingService;
    @Resource
    private TAddressService addressService;

    @Override
    public FareCalculateResultVO calculateFare(FareCalculateDTO dto) {
        FareCalculateResultVO result = new FareCalculateResultVO();

        // 1.获取商户的默认地址
        TAddress address = this.addressService.getOne(new LambdaQueryWrapper<TAddress>()
                .eq(TAddress::getMerchantId, dto.getMerchantId())
                .eq(TAddress::getIsDefault, 1)
                .eq(TAddress::getIsDelete, 0));
        if (ObjectUtil.isNull(address)) {
            throw new ServiceException("无法获取商户的默认地址");
        }

        // 2. 计算直线距离（公里）
        BigDecimal straightLineBigDecimal = DistanceUtil.formatDistanceInKilometers(
                dto.getLatitude(), dto.getLongitude(),
                address.getLatitude(), address.getLongitude()
        );

        // 3.根据时间段判断是否白天时间段
        LocalDateTime appointmentStartTime = dto.getAppointmentStartTime();
        boolean isDay = isDayTimePeriod(appointmentStartTime);

        // 4. 获取商户车费配置
        BigDecimal merchantFreeKm = getMerchantFreeKm(dto.getMerchantId(), dto.getProjectId(), isDay);

        // 5. 计算【打车距离】（即计费里程）
        if (ObjectUtil.isNull(straightLineBigDecimal)) {
            throw new ServiceException("距离未知");
        }
        BigDecimal effectiveDistance = straightLineBigDecimal.subtract(merchantFreeKm);
        if (effectiveDistance.compareTo(BigDecimal.ZERO) < 0) {
            effectiveDistance = BigDecimal.ZERO;
        }
        log.info("直线距离 {} km, 商户免车费距离 {} km -> 打车距离 {} km",
                straightLineBigDecimal, merchantFreeKm, effectiveDistance);

        // 6. 获取城市车费规则（用于最终计费）
        TFareSettingVo cityFare = fareSettingService.getFareSetting(appointmentStartTime, dto.getCityCode());
        if (ObjectUtil.isNull(cityFare)) {
            throw new ServiceException("未找到城市[" + dto.getCityCode() + "]的车费配置");
        }

        // 7. 使用城市规则计算费用
        BigDecimal baseFare = cityFare.getBaseFare();          // 起步价
        BigDecimal baseDistance = cityFare.getBaseDistance();  // 起步距离（公里）
        BigDecimal additionalFarePer = cityFare.getAdditionalFarePer(); // 超出后每公里价格

        BigDecimal estimatedFare;
        boolean isFree;

        // 如果打车距离为 0，表示全程被商户免车费覆盖，直接免费
        if (effectiveDistance.compareTo(BigDecimal.ZERO) <= 0) {
            estimatedFare = BigDecimal.ZERO;
            isFree = true;
        } else {
            // 打车距离 > 0，才进入城市计费逻辑
            BigDecimal exceedDistance = effectiveDistance.subtract(baseDistance);
            if (exceedDistance.compareTo(BigDecimal.ZERO) <= 0) {
                // 在起步距离内（但打车距离 > 0）
                estimatedFare = baseFare;
                isFree = false;
            } else {
                // 超出起步距离
                BigDecimal extraFare = exceedDistance.multiply(additionalFarePer).setScale(2, RoundingMode.HALF_UP);
                estimatedFare = baseFare.add(extraFare).setScale(2, RoundingMode.HALF_UP);
                isFree = false;
            }
        }

        // 8. 设置结果
        result.setFreeKm(merchantFreeKm);
        result.setBaseFare(baseFare);
        result.setBaseDistance(baseDistance);
        result.setAdditionalFarePer(additionalFarePer);
        result.setActualDistanceKm(straightLineBigDecimal.setScale(2, RoundingMode.HALF_UP)); // 原始直线距离（展示用）
        result.setEstimatedFare(estimatedFare);
        result.setIsFree(isFree);

        return result;
    }

    /**
     * 判断预约时间是否属于白天时间段
     *
     * @param appointmentStartTime 预约开始时间
     * @return true表示是白天时间段，false表示不是白天时间段（可能是夜间或其他时间段）
     */
    @Override
    public boolean isDayTimePeriod(LocalDateTime appointmentStartTime) {
        // 提取预约时间的小时和分钟，仅用于时间段比较
        LocalTime appointmentTime = appointmentStartTime.toLocalTime();

        // 查询白天时间段配置
        List<SysDictData> dayTimeRanges = DictUtils.getSortedDictCache("day_time");

        if (CollUtil.isNotEmpty(dayTimeRanges) && dayTimeRanges.size() >= 2) {
            // 获取开始时间和结束时间
            LocalTime dayStartTime = parseTime(CollUtil.getFirst(dayTimeRanges).getDictValue()); // 如 7:30
            LocalTime dayEndTime = parseTime(CollUtil.getLast(dayTimeRanges).getDictValue());   // 如 19:30

            // 判断是否在白天时间段范围内
            return isTimeInRange(appointmentTime, dayStartTime, dayEndTime);
        }

        // 如果没有找到白天时间段配置，默认返回false
        return false;
    }

    /**
     * 解析时间字符串为LocalTime
     */
    private LocalTime parseTime(String timeStr) {
        // 处理可能的格式差异，比如"7:30"转为"07:30"
        if (!timeStr.contains(":")) {
            throw new IllegalArgumentException("无效的时间格式: " + timeStr);
        }

        String[] parts = timeStr.split(":");
        if (parts.length == 2) {
            int hour = Integer.parseInt(parts[0]);
            int minute = Integer.parseInt(parts[1]);
            return LocalTime.of(hour, minute);
        } else {
            throw new IllegalArgumentException("无效的时间格式: " + timeStr);
        }
    }

    /**
     * 判断时间是否在时间段范围内（不跨越午夜）
     */
    private boolean isTimeInRange(LocalTime targetTime, LocalTime startTime, LocalTime endTime) {
        // 如果开始时间小于结束时间（同一天内）
        if (startTime.isBefore(endTime)) {
            return (targetTime.equals(startTime) || targetTime.isAfter(startTime)) &&
                    (targetTime.equals(endTime) || targetTime.isBefore(endTime));
        } else if (startTime.isAfter(endTime)) {
            // 如果开始时间大于结束时间（跨越午夜），这应该是夜间时间段
            return false;
        } else {
            // 如果开始时间等于结束时间
            return targetTime.equals(startTime);
        }
    }

    /**
     * 保存免车费设置信息
     *
     * @param
     * @param dto
     * @return
     */
    @Override
    public void saveOrUpdateFee(DriverFeeDTO dto) {
        // 1. 基础校验：检查是否有空值 (对应UI中的“判断必填项是否为空”)
        validateInput(dto);

        if (dto.getMode() == 1) {
            // --- 模式一：统一设置 ---
            // 逻辑：删除该用户所有具体的项目配置，只保留一条 categoryId=null 的记录
            baseMapper.delete(new LambdaQueryWrapper<MaProjectFareSetting>()
                    .eq(MaProjectFareSetting::getMerchantId, dto.getMerchantId()));

            MaProjectFareSetting config = new MaProjectFareSetting();
            config.setMerchantId(dto.getMerchantId());
            config.setProjectId(null);
            config.setDayFreeKm(dto.getUnifiedConfig().getDayFreeKm());
            config.setNightFreeKm(dto.getUnifiedConfig().getNightFreeKm());
            baseMapper.insert(config);

        } else if (dto.getMode() == 2) {
            // --- 模式二：按项目设置 ---
            // 逻辑：先删除旧数据，再批量插入新数据
            baseMapper.delete(new LambdaQueryWrapper<MaProjectFareSetting>()
                    .eq(MaProjectFareSetting::getMerchantId, dto.getMerchantId()));

            List<MaProjectFareSetting> list = new ArrayList<>();
            for (DriverFeeDTO.CategoryFeeItem item : dto.getCategoryConfigs()) {
                MaProjectFareSetting config = new MaProjectFareSetting();
                config.setMerchantId(dto.getMerchantId());
                config.setIsUnified(0);
                config.setProjectId(item.getCategoryId());
                config.setProjectName(item.getCategoryName());
                config.setDayFreeKm(item.getDayFreeKm());
                config.setNightFreeKm(item.getNightFreeKm());
                list.add(config);
            }
            // 批量保存
            for (MaProjectFareSetting config : list) {
                baseMapper.insert(config);
            }
        }

    }

    /**
     * 校验输入是否合法 (对应UI中的 Toast 提示逻辑)
     */
    private void validateInput(DriverFeeDTO dto) {
        if (dto.getMode() == 1) {
            if (dto.getUnifiedConfig() == null ||
                    dto.getUnifiedConfig().getDayFreeKm() == null ||
                    dto.getUnifiedConfig().getNightFreeKm() == null) {
                throw new RuntimeException("请输入完整的统一设置里程");
            }
        } else if (dto.getMode() == 2) {
            if (CollectionUtils.isEmpty(dto.getCategoryConfigs())) {
                throw new RuntimeException("请至少配置一个项目的免车费");
            }
            for (DriverFeeDTO.CategoryFeeItem item : dto.getCategoryConfigs()) {
                if (item.getDayFreeKm() == null || item.getNightFreeKm() == null) {
                    throw new RuntimeException("分类ID[" + item.getCategoryId() + "]的里程设置不完整");
                }
            }
        }
    }

    /**
     * 获取商户当前适用的免车费距离
     *
     * @param merchantId 商户ID
     * @param projectId  项目ID
     * @param isDay      是否为白天 (true: 白天, false: 夜间)
     * @return 适用的免车费距离，如果未配置或配置无效则返回 BigDecimal.ZERO
     */
    @Override
    public BigDecimal getMerchantFreeKm(Long merchantId, Long projectId, boolean isDay) {
        LambdaQueryWrapper<MaProjectFareSetting> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(MaProjectFareSetting::getMerchantId, merchantId)
                .eq(MaProjectFareSetting::getIsDelete, 0);
        List<MaProjectFareSetting> configList = this.baseMapper.selectList(wrapper);

        MaProjectFareSetting finalConfig = null;

        if (CollUtil.isNotEmpty(configList)) {
            // 先查找是否存在统一配置 (isUnified = 1)
            Optional<MaProjectFareSetting> unifiedOpt = configList.stream()
                    .filter(c -> ObjectUtil.equals(1, c.getIsUnified()))
                    .findFirst();

            if (unifiedOpt.isPresent()) {
                finalConfig = unifiedOpt.get();
            } else {
                // 查找匹配的项目配置
                log.info("商户[{}]不存在统一配置，根据projectId[{}]进行匹配", merchantId, projectId);

                Optional<MaProjectFareSetting> projectConfigOpt = configList.stream()
                        .filter(item -> item.getProjectId() != null && item.getProjectId().equals(projectId))
                        .findFirst();

                if (projectConfigOpt.isPresent()) {
                    // 找到了对应项目的配置
                    finalConfig = projectConfigOpt.get();
                }
            }
        }

        BigDecimal merchantFreeKm = BigDecimal.ZERO;

        if (ObjectUtil.isNotNull(finalConfig)) {

            // 商户配置的免车费距离（用于扣减）
            merchantFreeKm = isDay ? finalConfig.getDayFreeKm() : finalConfig.getNightFreeKm();

            if (ObjectUtil.isNull(merchantFreeKm) || merchantFreeKm.compareTo(BigDecimal.ZERO) <= 0) {
                merchantFreeKm = BigDecimal.ZERO;
                log.info("商户[{}]配置的免车费距离为 null 或 <= 0, 视为 0", merchantId);
            } else {
                log.info("商户[{}]使用配置ID={}, 免费公里数: {}", merchantId, finalConfig.getId(), merchantFreeKm);
            }
        }
        return merchantFreeKm;
    }
}
