package com.clx.performance.service.impl.breakcontract;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.breakcontract.BreakContractDriverRecordDao;
import com.clx.performance.dao.breakcontract.BreakContractDriverRuleDao;
import com.clx.performance.enums.BreakContractRecordEnum;
import com.clx.performance.enums.InternalMessageTemplateEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.TruckDemandEnum;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.breakcontract.BreakContractDriverRecord;
import com.clx.performance.model.breakcontract.BreakContractDriverRule;
import com.clx.performance.param.app.breakcontract.DriverPageBreakContractDriverRecordParam;
import com.clx.performance.param.pc.breakcontract.carrier.BreakContractDriverRecordAddParam;
import com.clx.performance.param.pc.breakcontract.carrier.PageBreakContractDriverRecordParam;
import com.clx.performance.service.IntegralRecordService;
import com.clx.performance.service.SendInternalMessageService;
import com.clx.performance.service.breakcontract.BreakContractDriverRecordService;
import com.clx.performance.service.breakcontract.BreakContractMqService;
import com.clx.performance.service.impl.UniqueOrderNumService;
import com.clx.performance.vo.app.breakcontract.DriverBreakContractDriverRecordVO;
import com.clx.performance.vo.pc.breakcontract.carrier.BreakContractDriverRecordVO;
import com.clx.performance.vo.pc.breakcontract.carrier.BreakContractDriverRuleVO;
import com.msl.common.utils.LocalDateTimeUtils;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Objects;

/**
 * @author liruixin
 * Date 2023-10-24
 * Time 16:02
 */
@Slf4j
@Service
public class BreakContractDriverRecordServiceImpl  implements BreakContractDriverRecordService {

    @Autowired
    private OrderGoodsDao orderGoodsDao;
    @Autowired
    private OrderChildDao orderChildDao;

    @Autowired
    private BreakContractDriverRecordDao breakContractDriverRecordDao;
    @Autowired
    private BreakContractDriverRuleDao breakContractDriverRuleDao;

    @Autowired
    private BreakContractMqService breakContractMqService;
    @Autowired
    private UniqueOrderNumService uniqueOrderNumService;
    @Autowired
    private IntegralRecordService integralRecordService;
    @Autowired
    SendInternalMessageService sendInternalMessageService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveRecord(BreakContractDriverRecordAddParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        Long userNo = loginUserInfo.getUserNo();

        String breakNo = breakNoGenerate();
        OrderChild orderChild = orderChildDao.getByChildNo(param.getChildNo()).orElseThrow(PerformanceResultEnum.ORDER_CHILD_NO_FOUND);

        LocalDateTime time = LocalDateTime.now();

        BreakContractDriverRecord record = new BreakContractDriverRecord();
        record.setBreakNo(breakNo);
        record.setTriggerType(BreakContractRecordEnum.TriggerType.MANUAL.getCode());
        record.setFigure(param.getFigure());
        record.setRemark(param.getRemark());

        if (Objects.equals(param.getBreakContractPartyType(), BreakContractRecordEnum.BreakContractPartyType.DRIVER.getCode())) {
            record.setBreakContractPartyType(BreakContractRecordEnum.BreakContractPartyType.DRIVER.getCode());
            if (param.getTimeLimit() != null) {
                record.setTimeLimit(param.getTimeLimit());
                record.setLimitTime(time.plusSeconds(param.getTimeLimit().multiply(BigDecimal.valueOf(3600L)).intValue()));
            }
        }
        else {
            record.setBreakContractPartyType(BreakContractRecordEnum.BreakContractPartyType.PLATFORM.getCode());
        }

        record.setChildNo(param.getChildNo());
        record.setTruckNo(orderChild.getTruckNo());
        record.setTruckOwnUserNo(orderChild.getTruckOwnUserNo());
        record.setTruckOwnName(orderChild.getTruckOwnName());
        record.setDriverUserNo(orderChild.getDriverUserNo());
        record.setDriverName(orderChild.getDriverName());

        record.setCreateBy(userNo);
        record.setCreateName(loginUserInfo.getUserName());
        record.setCreateTime(time);

        breakContractDriverRecordDao.saveEntity(record);
        // 发送mq (违约记录新增)
        breakContractMqService.driverRecordAdd(record.getId());

        // 保存平台补偿积分
        if (Objects.equals(param.getBreakContractPartyType(), BreakContractRecordEnum.BreakContractPartyType.PLATFORM.getCode())) {
            integralRecordService.addPlatformCompensationRecord(record.getTruckNo());
        }

        //司机违约通知 站内信
        sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
                InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
                InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(breakNo),null,null);


    }

    @Override
    public IPage<BreakContractDriverRecordVO> pageRecord(PageBreakContractDriverRecordParam param) {
        return breakContractDriverRecordDao.pageByParam(param);

    }

    @Override
    public IPage<DriverBreakContractDriverRecordVO> driverPageRecord(DriverPageBreakContractDriverRecordParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        Long userNo = loginUserInfo.getUserNo();
        param.setUserNo(userNo);

        return breakContractDriverRecordDao.driverPageByParam(param);

    }

    private String breakNoGenerate() {
        return "WYD"+uniqueOrderNumService.getUniqueOrderNum(
                LocalDateTimeUtils.convertLocalDateTimeToString(LocalDateTime.now(), LocalDateTimeUtils.DATE_DAY));
    }

    @Override
    public void saveDriverRecordOfOrderChildCancel(OrderChild orderChild, Long createBy, String createName) {
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo())
                .orElseThrow(PerformanceResultEnum.ORDER_GOODS_NO_FOUND);
        //自由车辆的货单，不产生违约
        if(Objects.equals(orderGoods.getTruckDemand(), TruckDemandEnum.TruckType.OWNER_CAR.getCode())){
            return;
        }
        BreakContractDriverRecord record = new BreakContractDriverRecord();

        BreakContractDriverRule rule = breakContractDriverRuleDao.getEntityByKey(1).orNull();
        if (rule == null) {return;}

        BreakContractDriverRuleVO breakContractDriverRuleVO = JSON.parseObject(rule.getRuleJson(), BreakContractDriverRuleVO.class);

        // 费用计算
        BigDecimal figure = orderChildCancelFigureCalc(orderChild, breakContractDriverRuleVO);
        record.setTriggerType(BreakContractRecordEnum.TriggerType.SYSTEM.getCode());
        record.setBreakContractPartyType(BreakContractRecordEnum.BreakContractPartyType.DRIVER.getCode());
        record.setBreakNo(breakNoGenerate());
        record.setFigure(figure);
        record.setRemark("司机取消运单");

        record.setChildNo(orderChild.getChildNo());
        record.setTruckNo(orderChild.getTruckNo());
        record.setTruckOwnUserNo(orderChild.getTruckOwnUserNo());
        record.setTruckOwnName(orderChild.getTruckOwnName());
        record.setDriverUserNo(orderChild.getDriverUserNo());
        record.setDriverName(orderChild.getDriverName());

        record.setCreateBy(0L);
        record.setCreateName("系统");

        breakContractDriverRecordDao.saveEntity(record);

        // 发送mq (违约记录新增)
        breakContractMqService.driverRecordAdd(record.getId());

        //司机违约通知 站内信
        sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
                InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
                InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);

        // 司机违约通知APP站内信
        sendInternalMessageService.sendInternalMessageMq(
                // APP
                InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
                // 业务类型
                InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
                // 司机违约规则配置-司机取消
                InternalMessageTemplateEnum.DRIVER_CANCEL_ORDER_CODE,
                // 运单编号、接单时间小于X小时、收费X元
                List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseTime(),
                        breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
                null,
                orderChild.getDriverUserNo());
    }

    @Override
    public void saveDriverRecordOfArriveSendAddressTimeout(OrderChild orderChild, Long createBy, String createName) {
        BreakContractDriverRecord record = new BreakContractDriverRecord();

        // 1小时内不违约
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(PerformanceResultEnum.ORDER_GOODS_NO_FOUND);
        //自由车辆的货单，不产生违约
        if(Objects.equals(orderGoods.getTruckDemand(), TruckDemandEnum.TruckType.OWNER_CAR.getCode())){
            return;
        }
        if (!orderChild.getPayTime().plusHours(1).isBefore(orderGoods.getLastArriveReceiveTime())){return;}

        BreakContractDriverRule rule = breakContractDriverRuleDao.getEntityByKey(1).orNull();
        if (rule == null) {return;}

        BreakContractDriverRuleVO breakContractDriverRuleVO = JSON.parseObject(rule.getRuleJson(), BreakContractDriverRuleVO.class);

        // 费用计算
        BigDecimal figure = orderChildArriveSendAddressTimeoutFigureCalc(orderChild, orderGoods, breakContractDriverRuleVO);
        record.setTriggerType(BreakContractRecordEnum.TriggerType.SYSTEM.getCode());
        record.setBreakContractPartyType(BreakContractRecordEnum.BreakContractPartyType.DRIVER.getCode());
        record.setBreakNo(breakNoGenerate());
        record.setFigure(figure);
        record.setRemark("到达货源地超时取消");

        record.setChildNo(orderChild.getChildNo());
        record.setTruckNo(orderChild.getTruckNo());
        record.setTruckOwnUserNo(orderChild.getTruckOwnUserNo());
        record.setTruckOwnName(orderChild.getTruckOwnName());
        record.setDriverUserNo(orderChild.getDriverUserNo());
        record.setDriverName(orderChild.getDriverName());

        record.setCreateBy(0L);
        record.setCreateName("系统");

        breakContractDriverRecordDao.saveEntity(record);

        // 发送mq (违约记录新增)
        breakContractMqService.driverRecordAdd(record.getId());

        //司机违约通知 站内信
        sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
                InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
                InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);

        // 司机违约通知APP站内信
        sendInternalMessageService.sendInternalMessageMq(
                // APP
                InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
                // 业务类型
                InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
                // 未按约定时间到达货源地
                InternalMessageTemplateEnum.DRIVER_ARRIVE_SOURCE_LOCAL_TIMEOUT_CODE,
                // 运单编号、收费X元
                List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
                null,
                orderChild.getDriverUserNo());

    }

    @Override
    public void saveDriverRecordOfArriveReceiveAddress(OrderChild orderChild, Long createBy, String createName) {
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(PerformanceResultEnum.ORDER_GOODS_NO_FOUND);
        //自由车辆的货单，不产生违约
        if(Objects.equals(orderGoods.getTruckDemand(), TruckDemandEnum.TruckType.OWNER_CAR.getCode())){
            return;
        }
        if (!orderChild.getArriveReceiveTime().isAfter(orderGoods.getLastArriveReceiveTime())) {return;}

        BreakContractDriverRule rule = breakContractDriverRuleDao.getEntityByKey(1).orNull();
        if (rule == null) {return;}

        BreakContractDriverRuleVO breakContractDriverRuleVO = JSON.parseObject(rule.getRuleJson(), BreakContractDriverRuleVO.class);

        // 费用计算
        BigDecimal figure = arriveReceiveAddressFigureCalc(orderChild, orderGoods, breakContractDriverRuleVO);
        BreakContractDriverRecord record = new BreakContractDriverRecord();
        record.setTriggerType(BreakContractRecordEnum.TriggerType.SYSTEM.getCode());
        record.setBreakContractPartyType(BreakContractRecordEnum.BreakContractPartyType.DRIVER.getCode());
        record.setBreakNo(breakNoGenerate());
        record.setFigure(figure);
        record.setRemark("到达目的地超时");

        record.setChildNo(orderChild.getChildNo());
        record.setTruckNo(orderChild.getTruckNo());
        record.setTruckOwnUserNo(orderChild.getTruckOwnUserNo());
        record.setTruckOwnName(orderChild.getTruckOwnName());
        record.setDriverUserNo(orderChild.getDriverUserNo());
        record.setDriverName(orderChild.getDriverName());

        record.setCreateBy(0L);
        record.setCreateName("系统");
        breakContractDriverRecordDao.saveEntity(record);

        // 发送mq (违约记录新增)
        breakContractMqService.driverRecordAdd(record.getId());

        //司机违约通知 站内信
        sendInternalMessageService.sendInternalMessageMq(InternalMessageTemplateEnum.PlatformType.CARRIER.getCode(),
                InternalMessageTemplateEnum.BusinessType.WAIT_APPROVED_ITEM.getCode(),
                InternalMessageTemplateEnum.CUSTOM_DRIVER_TRIGGER_BREAK_CONTRACT_CODE, List.of(record.getBreakNo()),null,null);

        // 司机违约通知APP站内信
        sendInternalMessageService.sendInternalMessageMq(
                // APP
                InternalMessageTemplateEnum.PlatformType.DRIVER_APP.getCode(),
                // 业务类型
                InternalMessageTemplateEnum.BusinessType.APP_SECOND_CLASSIFICATION.getCode(),
                // 未按约定时间到达目的地（到达目的地超时）
                InternalMessageTemplateEnum.DRIVER_ARRIVE_DESTINATION_TIMEOUT_CODE,
                // 运单编号、收费X元
                List.of(orderChild.getChildNo(), breakContractDriverRuleVO.getDriverCancelRule().getBaseFigure()),
                null,
                orderChild.getDriverUserNo());
    }

    @Override
    public BigDecimal getBreakContractFigure(String childNo) {
        OrderChild orderChild = orderChildDao.getByChildNo(childNo).orElseThrow(PerformanceResultEnum.ORDER_CHILD_NO_FOUND);
        //自由车辆违约金额返回0元
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(PerformanceResultEnum.ORDER_GOODS_NO_FOUND);
        if(Objects.equals(TruckDemandEnum.TruckType.OWNER_CAR.getCode(),orderGoods.getTruckDemand())){
              return new BigDecimal("0.00");
        }
        BreakContractDriverRule rule = breakContractDriverRuleDao.getEntityByKey(1).orNull();
        if (rule == null) {return BigDecimal.ZERO;}

        BreakContractDriverRuleVO breakContractDriverRuleVO = JSON.parseObject(rule.getRuleJson(), BreakContractDriverRuleVO.class);
        orderChild.setCancelTime(LocalDateTime.now());

        // 费用计算
        BigDecimal figure = orderChildCancelFigureCalc(orderChild, breakContractDriverRuleVO);

        return figure.movePointLeft(2);
    }

    /**
     * 费用计算 （运单取消）
     */
    private BigDecimal orderChildCancelFigureCalc(OrderChild orderChild, BreakContractDriverRuleVO rule){
        long time = com.clx.performance.utils.LocalDateTimeUtils.betweenSecond(orderChild.getPayTime(), orderChild.getCancelTime());
        long baseTime = rule.getDriverCancelRule().getBaseTime().multiply(BigDecimal.valueOf(3600)).setScale(0, RoundingMode.HALF_UP).longValue();

        if (time < baseTime) {
            return rule.getDriverCancelRule().getBaseFigure().movePointRight(2);
        }
        else {
            BigDecimal money = rule.getDriverCancelRule().getBaseFigure();
            money = money.add(BigDecimal.valueOf(time-baseTime).divide(BigDecimal.valueOf(1800), 0, RoundingMode.UP).multiply(rule.getDriverCancelRule().getFigurePerHour()));
            return money.movePointRight(2);
        }
    }

    /**
     * 费用计算 （运单取消）
     */
    private BigDecimal orderChildArriveSendAddressTimeoutFigureCalc(OrderChild orderChild, OrderGoods orderGoods, BreakContractDriverRuleVO rule){
        long time = com.clx.performance.utils.LocalDateTimeUtils.betweenSecond(orderChild.getPayTime(), orderGoods.getLastArriveSendTime());
        long baseTime = 3600;
        time = time-baseTime;

        BigDecimal money = BigDecimal.valueOf(time).divide(BigDecimal.valueOf(3600), 2, RoundingMode.HALF_UP).multiply(rule.getSendAddressRule().getFigurePerHour()).setScale(2, RoundingMode.HALF_UP);
        return money.movePointRight(2);
    }



    /**
     * 费用计算 (到达目的地超时)
     */
    private BigDecimal arriveReceiveAddressFigureCalc(OrderChild orderChild, OrderGoods orderGoods, BreakContractDriverRuleVO rule){
        long time = com.clx.performance.utils.LocalDateTimeUtils.betweenSecond(orderGoods.getLastArriveReceiveTime(), orderChild.getArriveReceiveTime());

        BigDecimal money = BigDecimal.valueOf(time).divide(BigDecimal.valueOf(3600), 0, RoundingMode.UP).multiply(rule.getReceiveAddressRule().getFigurePerHour()).multiply(orderChild.getWeight()).setScale(2, RoundingMode.HALF_UP);
        return money.movePointRight(2);
    }

    @Override
    public Integer getChildTruckDemand(String childNo) {
        OrderChild child = orderChildDao.getByChildNo(childNo).orElseThrow(PerformanceResultEnum.ORDER_CHILD_NO_FOUND);
        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(child.getOrderGoodsNo()).orElseThrow(PerformanceResultEnum.ORDER_GOODS_NO_FOUND);
        if(Objects.equals(orderGoods.getTruckDemand(),TruckDemandEnum.TruckType.OWNER_CAR.getCode())){
            return 1;
        }
        return 0;
    }
}
