package com.clx.performance.service.impl;

import com.clx.performance.dao.*;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.enums.integral.IntegralRecordEnum;
import com.clx.performance.model.*;
import com.clx.performance.param.mq.*;
import com.clx.performance.service.*;
import com.clx.performance.service.integral.IntegralRuleService;
import com.clx.performance.utils.LocalDateTimeUtils;
import com.clx.performance.vo.pc.integral.AppIntegralRuleVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
public class IntegralMqHandlerServiceImpl implements IntegralMqHandlerService {

    @Autowired
    private IntegralStatisticsDao integralStatisticsDao;
    @Autowired
    private IntegralRecordDao integralRecordDao;
    @Autowired
    private IntegralTruckDao integralTruckDao;
    @Autowired
    private IntegralOrderDao integralOrderDao;
    @Autowired
    private OrderChildDao orderChildDao;
    @Autowired
    private OrderGoodsDao orderGoodsDao;

    @Autowired
    private IntegralStatisticsService integralStatisticsService;

    @Autowired
    private IntegralRecordService integralRecordService;

    @Autowired
    private IntegralRuleService integralRuleService;

    /**
     * 车辆新增
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void truckAdd(IntegralTuckAddMqParam mq){
        String truckNo = mq.getTruckNo();

        boolean existFlag = integralTruckDao.existByTruckNo(truckNo);
        if (existFlag) {return;}

        IntegralTruck truck = new IntegralTruck();
        truck.setTruckNo(truckNo);
        truck.setDriverName(mq.getDriverName());
        truck.setDriverMobile(mq.getDriverMobile());
        truck.setEchelon(1);

        LocalDateTime statisticsDate = LocalDateTimeUtils.getStartWeek();
        int protectionIntegral = integralStatisticsService.protectionIntegralCalc(statisticsDate);
        int baseIntegral = 100;

        // 初始化统计
        IntegralStatistics statistics = new IntegralStatistics();
        statistics.setTruckNo(truckNo);
        statistics.setStatisticsDate(statisticsDate);
        statistics.setIntegralBase(0);
        statistics.setIntegral(protectionIntegral+baseIntegral);   //保护分+基础分
        statistics.setRank(1);
        integralStatisticsDao.saveEntity(statistics);

        IntegralStatistics statisticsNext = new IntegralStatistics();
        statisticsNext.setTruckNo(truckNo);
        statisticsNext.setStatisticsDate(statistics.getStatisticsDate().plusDays(7));
        statisticsNext.setIntegralBase(0);
        statisticsNext.setIntegral(0);
        statisticsNext.setRank(1);
        integralStatisticsDao.saveEntity(statisticsNext);

        // 新增车辆
        truck.setIntegral(statistics.getIntegral());
        integralTruckDao.saveEntity(truck);

        // 新增积分记录
        integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(), IntegralRecord.type.PROTECTION.getValue(), protectionIntegral, "新用户");
        integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(), IntegralRecord.type.BASE.getValue(), baseIntegral, "基础分");

        // 实时积分统计
        integralRealTimeStatistics(statistics.getId());

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderGoodsAdd(IntegralOrderAddMqParam mq) {

        boolean existFlag = integralOrderDao.existByOrderGoodsNo(mq.getOrderGoodsNo());
        if (existFlag) {return;}

        IntegralOrder order = new IntegralOrder();
        order.setOrderGoodsNo(mq.getOrderGoodsNo());
        order.setSendAddressId(mq.getSendAddressId());
        order.setSendAddress(mq.getSendAddress());
        order.setReceiveAddressId(mq.getReceiveAddressId());
        order.setReceiveAddress(mq.getReceiveAddress());
        order.setOrderType(mq.getOrderType());
        order.setTruckEchelon(1);
        integralOrderDao.saveEntity(order);

    }

    /**
     * 积分记录新增
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void recordAdd(IntegralRecordAddMqParam mq){


    }

    /**
     * 下周车辆初始化（新增统计车辆） （周3、周7 晚上）
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void nextWeekTruckInit(IntegralNextWeekTruckInitMqParam mq){
        LocalDateTime statisticsDateCurrent = LocalDateTimeUtils.parseTime(mq.getStatisticsDate());

        LocalDateTime statisticsDateNext = statisticsDateCurrent.plusDays(7);

        // 查找本周车辆
        List<IntegralStatistics> list = integralStatisticsDao.selectByStatisticsDate(statisticsDateCurrent);

        // 查找下周车辆
        List<IntegralStatistics> nextList = integralStatisticsDao.selectByStatisticsDate(statisticsDateNext);
        List<String> truckNoNextList = nextList.stream().map(item -> item.getTruckNo()).collect(Collectors.toList());

        List<IntegralStatistics> newList = new ArrayList<>();
        for (IntegralStatistics item : list) {
            if (truckNoNextList.contains(item.getTruckNo())) {continue;}

            IntegralStatistics statistics = new IntegralStatistics();
            statistics.setTruckNo(item.getTruckNo());
            statistics.setStatisticsDate(statisticsDateNext);
            statistics.setIntegralBase(0);
            statistics.setIntegral(0);
            statistics.setRank(1);

            newList.add(statistics);
        }
        log.info("初始化下周车辆，size:{}",newList.size());

        if (newList.isEmpty()) {return;}

        // 新增下周车辆
        integralStatisticsDao.batchSaveEntity(newList);

    }

    /**
     * 车辆周统计 (统计周初始积分)
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void weekTruckStatistics(IntegralWeekTruckStatisticsMqParam mq){

        if (StringUtils.isNotBlank(mq.getTruckNo())){
            // 基础分初始化
            truckBaseIntegralInit(mq.getTruckNo(), mq.getStatisticsDate());
            return;
        }

        // 更新本周实时排名
        integralRealTimeRankStatistics(LocalDateTimeUtils.parseTime(mq.getStatisticsDate()));
    }

    /**
     * 新一周基础积分初始化
     */
    private void truckBaseIntegralInit(String truckNo, String statisticsDate){
        IntegralTruck truck = integralTruckDao.getByTruckNo(truckNo).orNull();
        if (null == truck) {return;}

        IntegralStatistics statistics = integralStatisticsDao.selectByTruckNoAndStatisticsDate(truck.getTruckNo(), statisticsDate).orNull();
        if (null == statistics) {return;}

        // 新车保护分
        newTruckProtection(truck, statistics);

        // 周结算分
        truckWeekSettlement(truck, statistics);

        integralStatisticsDao.updateIntegral(statistics);

        truck.setIntegral(statistics.getIntegral());
        integralTruckDao.updateIntegral(truck);

    }

    /**
     * 新车保护分
     */
    private void newTruckProtection(IntegralTruck truck, IntegralStatistics statistics){
        LocalDateTime statisticsDate = statistics.getStatisticsDate();

        // 超过保护期
        if (truck.getCreateTime().isBefore(statisticsDate.minusDays(7))) {return;}

        // 已保护不处理
        IntegralRecord record = integralRecordDao.selectByStatisticsIdAndType(statistics.getId(), IntegralRecord.type.PROTECTION.getValue());
        if (null != record) {return;}

        // 计算新车积分
        int integral = integralStatisticsService.protectionIntegralCalc(truck.getCreateTime(), statisticsDate);
        if (integral == 0) {return;}

        statistics.setIntegral(statistics.getIntegral()+integral);
        integralStatisticsDao.updateIntegral(statistics);

        integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(), IntegralRecord.type.PROTECTION.getValue(), integral, "新用户");

    }

    /**
     * 上周结算分
     */
    private void truckWeekSettlement(IntegralTruck truck, IntegralStatistics statistics){
        int integral;

        // 已结算不处理
        IntegralRecord record = integralRecordDao.selectByStatisticsIdAndType(statistics.getId(), IntegralRecord.type.SETTLEMENT.getValue());
        if (null != record) {return;}

        String statisticsDatePre = LocalDateTimeUtils.formatTime(statistics.getStatisticsDate().minusDays(7));

        // 查找上周统计数据
        IntegralStatistics statisticsPre = integralStatisticsDao.selectByTruckNoAndStatisticsDate(truck.getTruckNo(), statisticsDatePre).orNull();
        if (null == statisticsPre) {return;}

        // 查找总车数
        int truckSum = integralStatisticsDao.countByStatisticsDate(statisticsDatePre);

        if (statisticsPre.getRank() <= truckSum*0.1){
            integral = 300;
        }
        else if ( (statisticsPre.getRank() > truckSum*0.1) && (statisticsPre.getRank() <= truckSum*0.3)){
            integral = 200;
        }
        else if ( (statisticsPre.getRank() > truckSum*0.3) && (statisticsPre.getRank() <= truckSum*0.6)){
            integral = 100;
        }
        else if ( (statisticsPre.getRank() > truckSum*0.6) && (statisticsPre.getRank() <= truckSum*0.9)){
            integral = 60;
        }
        else {
            integral = 0;
        }
        if (integral == 0) {return;}

        statistics.setIntegral(statistics.getIntegral()+integral);
        integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(), IntegralRecord.type.SETTLEMENT.getValue(), integral, "上周结算");

    }

    /**
     * 新手保护取消
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void truckProtectionCancel(IntegralTruckProtectionCancelMqParam mq){
        IntegralTruck truck = integralTruckDao.getByTruckNo(mq.getTruckNo()).orNull();
        if (null == truck) {return;}

        IntegralStatistics statistics = integralStatisticsDao.selectByTruckNoAndStatisticsDate(truck.getTruckNo(), mq.getStatisticsDate()).orNull();
        if (null == statistics) {return;}

        IntegralRecord record = integralRecordDao.selectByStatisticsIdAndType(statistics.getId(), IntegralRecord.type.PROTECTION.getValue());
        IntegralRecord recordCancel = integralRecordDao.selectByStatisticsIdAndType(statistics.getId(), IntegralRecord.type.PROTECTION_CANCEL.getValue());
        if (null != recordCancel) {return;}
        int integral = -record.getIntegral();

        integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(), IntegralRecord.type.PROTECTION_CANCEL.getValue(), integral, "新用户过保护期");

        statistics.setIntegral(statistics.getIntegral()+integral);
        integralStatisticsDao.updateIntegral(statistics);

        truck.setIntegral(statistics.getIntegral());
        integralTruckDao.updateIntegral(truck);

        // 更新本周实时排名
        integralRealTimeRankStatistics(LocalDateTimeUtils.parseTime(mq.getStatisticsDate()));

    }

    /**
     * 运单结束
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void orderChildFinish(IntegralOrderChildFinishMqParam mq) {
        String statisticsDate = LocalDateTimeUtils.getWeekStart();

        // 查找规则
        AppIntegralRuleVO ruleInfo = integralRuleService.getRuleInfo();

        OrderChild orderChild = orderChildDao.getByChildNo(mq.getChildNo()).orNull();
        if (null == orderChild) {return;}

        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orNull();
        if (null == orderGoods) {return;}

        IntegralOrder integralOrder = integralOrderDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orNull();
        if (null == integralOrder){return;}

        IntegralStatistics statistics = integralStatisticsDao.selectByTruckNoAndStatisticsDate(orderChild.getTruckNo(), statisticsDate).orNull();
        if (null == statistics) {return;}

        IntegralTruck truck = integralTruckDao.getByTruckNo(orderChild.getTruckNo()).orNull();
        if (null == truck) {return;}

        int integral = 0;
        if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.ARRIVE_SEND_ADDRESS_TIMEOUT_CANCEL.getCode())){
            // 到达货源地超时
            integral = orderChildArriveSendAddress(statistics, ruleInfo);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.ARRIVE_RECEIVE_ADDRESS_TIMEOUT.getCode())){
            // 到达目的地超时
            integral = orderChildArriveReceiveAddress(statistics, ruleInfo, orderChild, orderGoods);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.DRIVER_CONFIRM.getCode())){
            // 司机确认收货
            integral = orderChildDriverConfirm(statistics, ruleInfo, orderChild);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.DRIVER_CANCEL.getCode())){
            // 司机取消
            integral = orderChildCancel(statistics, ruleInfo);
        }

        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.CARRIER_CANCEL.getCode())){
            // 承运取消
            integral = orderChildPlatformCancel(statistics, ruleInfo, orderChild);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.ARTIFICIAL_CANCEL.getCode())){
            // 客服取消
            integral = orderChildPlatformCancel(statistics, ruleInfo, orderChild);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.ORDER_CANCEL.getCode())){
            // 订单取消
            integral = orderChildPlatformCancel(statistics, ruleInfo, orderChild);
        }
        else if (Objects.equals(mq.getType(), IntegralOrderChildFinishMqParam.Type.ORDER_GOODS_CANCEL.getCode())){
            // 货单取消
            integral = orderChildPlatformCancel(statistics, ruleInfo, orderChild);
        }


        log.info("司机积分, 运单:{}, 累计积分:{}", orderChild.getChildNo(), integral);
        if (integral == 0) {return;}

        // 更新积分
        statistics.setIntegral(statistics.getIntegral()+integral);
        integralStatisticsDao.updateIntegral(statistics);

        truck.setIntegral(statistics.getIntegral());
        integralTruckDao.updateIntegral(truck);

        // 实时积分统计
        integralRealTimeStatistics(statistics.getId());
    }

    /**
     * 到达货源地超时
     */
    private int orderChildArriveSendAddress(IntegralStatistics statistics, AppIntegralRuleVO ruleInfo){

        int integralSum = 0;

        Integer cancelIntegral = -ruleInfo.getOrderChildTimeoutRule().getIntegralSendAddressTimeout();

        if (cancelIntegral < 0){
            integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(),
                    IntegralRecordEnum.Type.ORDER_CHILD_ARRIVE_SEND_ADDRESS_TIMEOUT_CANCEL.getValue(), cancelIntegral,
                    IntegralRecordEnum.Type.ORDER_CHILD_ARRIVE_SEND_ADDRESS_TIMEOUT_CANCEL.getMsg());
        }

        integralSum = cancelIntegral;

        return integralSum;

    }

    /**
     * 到达目的地超时
     */
    private int orderChildArriveReceiveAddress(IntegralStatistics statistics, AppIntegralRuleVO ruleInfo, OrderChild orderChild, OrderGoods orderGoods){

        int integralSum = 0;

        LocalDateTime lastArriveReceiveTime = orderGoods.getLastArriveReceiveTime();

        int receiveAddressTimeoutIntegral = 0;
        if (null != lastArriveReceiveTime && orderChild.getArriveReceiveTime().isAfter(lastArriveReceiveTime)){
            receiveAddressTimeoutIntegral = -ruleInfo.getOrderChildTimeoutRule().getIntegralSendAddressTimeout();
        }

        if (receiveAddressTimeoutIntegral < 0){
            integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(),
                    IntegralRecordEnum.Type.ORDER_CHILD_ARRIVE_RECEIVE_ADDRESS_TIMEOUT.getValue(), receiveAddressTimeoutIntegral,
                    IntegralRecordEnum.Type.ORDER_CHILD_ARRIVE_RECEIVE_ADDRESS_TIMEOUT.getMsg());
        }

        integralSum = receiveAddressTimeoutIntegral;

        return integralSum;
    }

    /**
     * 司机确认收货
     */
    private int orderChildDriverConfirm(IntegralStatistics statistics, AppIntegralRuleVO ruleInfo, OrderChild orderChild){

        LocalDateTime dateTimeDayStart = LocalDateTimeUtils.getDayStart();

        int integralSum = 0;

        // 完成量积分
        int completeNumIntegral = 0;
        String completeNumIntegralRemark="";
        List<String> enableOrderNoList = integralOrderDao.getAllOrderNoList();
        int finishNum = orderChildDao.countCompleteByTruckNoAndPayFinishTime(orderChild.getTruckNo(),
                LocalDateTimeUtils.formatTime(dateTimeDayStart),
                LocalDateTimeUtils.formatTime(orderChild.getConfirmTime()),
                enableOrderNoList);
        log.info("司机积分，车辆完成量，truckNo:{}, sum:{}", orderChild.getTruckNo(), finishNum);

        if (finishNum == 1){
            completeNumIntegral = ruleInfo.getOrderChildCompleteRule().getInteger1();
            completeNumIntegralRemark = "运单达量1单";
        }
        else if (finishNum == 2){
            completeNumIntegral = ruleInfo.getOrderChildCompleteRule().getInteger2();
            completeNumIntegralRemark = "运单达量2单";
        }
        else if (finishNum == 3){
            completeNumIntegral = ruleInfo.getOrderChildCompleteRule().getInteger3();
            completeNumIntegralRemark = "运单达量3单";
        }
        else if (finishNum == 4){
            completeNumIntegral = ruleInfo.getOrderChildCompleteRule().getInteger4();
            completeNumIntegralRemark = "运单达量4单";
        }
        else if (finishNum > 4){
            completeNumIntegral = 0;
        }

        if (completeNumIntegral > 0){
            integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(),
                    IntegralRecordEnum.Type.ORDER_CHILD_COMPLETE_NUM.getValue(), completeNumIntegral,
                    completeNumIntegralRemark);
        }

        integralSum = completeNumIntegral;

        return integralSum;
    }

    /**
     * 司机取消
     */
    private int orderChildCancel(IntegralStatistics statistics, AppIntegralRuleVO ruleInfo){

        int integralSum = 0;

        int cancelIntegral = -ruleInfo.getOrderChildCancelRule().getIntegralCancel();

        if (cancelIntegral < 0){
            integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(),
                    IntegralRecordEnum.Type.ORDER_CHILD_CANCEL.getValue(), cancelIntegral,
                    IntegralRecordEnum.Type.ORDER_CHILD_CANCEL.getMsg());
        }

        integralSum = cancelIntegral;

        return integralSum;

    }

    /**
     * 平台运单取消
     */
    private int orderChildPlatformCancel(IntegralStatistics statistics, AppIntegralRuleVO ruleInfo, OrderChild orderChild){

        int integralSum = 0;

        int integral = ruleInfo.getPlatformCompensationRule().getIntegralCancel();;

        Integer sum = integralRecordDao.sumByStatisticsIdAndTypes(statistics.getId(), Arrays.asList(IntegralRecordEnum.Type.ORDER_CHILD_PLATFORM_CANCEL.getValue()));
        if (sum == null) {sum = 0;}
        if (sum > ruleInfo.getPlatformCompensationRule().getIntegralCancelLimit()){
            log.info("平台取消补偿超上限，本次无效， childNo:{}", orderChild.getChildNo());
            integral = 0;
        }
        else if (sum+integral > ruleInfo.getPlatformCompensationRule().getIntegralCancelLimit()){
            integral = ruleInfo.getPlatformCompensationRule().getIntegralCancelLimit()-sum;
        }
        else {

        }

        if (integral > 0){
            integralRecordService.save(statistics.getId(), statistics.getStatisticsDate(), statistics.getTruckNo(),
                    IntegralRecordEnum.Type.ORDER_CHILD_PLATFORM_CANCEL.getValue(), integral,
                    IntegralRecordEnum.Type.ORDER_CHILD_PLATFORM_CANCEL.getMsg());
        }

        integralSum = integral;

        return integralSum;
    }

    /**
     * 更新实时积分
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void integralRealTimeStatistics(Integer statisticsId){
        IntegralStatistics statistics = integralStatisticsDao.selectById(statisticsId).orNull();
        if (null == statistics) {return;}

        Integer integral = integralRecordDao.sumIntegral(statisticsId);
        if (null == integral){return;}

        statistics.setIntegral(integral);

        // 更新车辆总积分
        integralStatisticsDao.updateIntegral(statistics);

        // 更新车辆积分
        integralTruckDao.updateIntegralByTruckNo(statistics.getTruckNo(), statistics.getIntegral());

        // 更新本周实时排名
        integralRealTimeRankStatistics(statistics.getStatisticsDate());
    }

    /**
     * 更新实时排名
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void integralRealTimeRankStatistics(LocalDateTime statisticsDate){

        List<IntegralStatistics> list = integralStatisticsDao.selectByStatisticsDate(statisticsDate);

        list.get(0).setRank(1);
        for (int i=1; i<list.size(); i++){
            if (list.get(i).getIntegral().equals(list.get(i-1).getIntegral())){list.get(i).setRank(list.get(i-1).getRank());}
            else {list.get(i).setRank(i+1);};
        }

        integralStatisticsDao.batchUpdateRank(list);

    }

    /**
     * 时间差
     */
    private Integer diffSecond(LocalDateTime startTime, LocalDateTime endTime){
        Duration duration = Duration.between(startTime, endTime);
        return (int)duration.getSeconds();
    }

}
