package com.clx.performance.service.impl;

import com.alibaba.druid.sql.visitor.functions.If;
import com.clx.order.enums.QuotationEnum;
import com.clx.performance.dao.*;
import com.clx.performance.dto.payment.PaymentDTO;
import com.clx.performance.enums.*;
import com.clx.performance.enums.settle.SettlementWayEnum;
import com.clx.performance.model.*;
import com.clx.performance.param.pc.PoundAuditParam;
import com.clx.performance.param.pc.payment.PayPlatformFeeParam;
import com.clx.performance.service.*;
import com.clx.performance.service.child.OrderChildPostService;
import com.clx.performance.vo.pc.OrderChildPoundAuditDetailVO;
import com.msl.common.exception.ServiceSystemException;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.AllArgsConstructor;
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.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.clx.performance.enums.OrderChildPoundAuditEnum.Status.APPROVED;
import static com.msl.common.utils.LocalDateTimeUtils.convertLocalDateTimeToDefaultString;

/**
 * @author liruixin
 * Date 2023-09-19
 * Time 13:25
 */
@Slf4j
@Service
@AllArgsConstructor
public class OrderChildPoundAuditServiceImpl  implements OrderChildPoundAuditService {

    private final OrderGoodsTruckBindDao orderGoodsTruckBindDao;
    private final OrderChildImageDao orderChildImageDao;

    private final OrderChildPoundAuditDao orderChildPoundAuditDao;

    private final OrderChildPoundLogDao orderChildPoundLogDao;

    private final OrderChildDao orderChildDao;

    private final OrderGoodsDao orderGoodsDao;

    private final OrderGoodsService orderGoodsService;

    private final OrderChildLogService orderChildLogService;
    private final OrderChildService orderChildService;
    private final PaymentService paymentService;
    private final OcrRecognitionDao ocrRecognitionDao;
    private final OrderChildPostService orderChildPostService;

    @Override
    public OrderChildPoundAuditDetailVO getPoundAuditDetail(String childNo) {
        OrderChildPoundAudit poundAuditDetail = orderChildPoundAuditDao.getPoundAuditDetail(childNo).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        List<OrderChildImage> loadImages = orderChildImageDao.getImages(childNo, OrderChildImage.Type.LOAD.getCode());
        List<OrderChildImage> unloadImages = orderChildImageDao.getImages(childNo, OrderChildImage.Type.UNLOAD.getCode());
        OrderChild orderChild = orderChildDao.getByChildNo(childNo).get();
        List<OcrRecognition> ocrRecognitionList = ocrRecognitionDao.listByField(OcrRecognition::getChildNo, childNo);
        Map<Integer, OcrRecognition> imageTypeOcrRecognitionMap = ocrRecognitionList.stream().collect(Collectors.toMap(OcrRecognition::getImageType, v -> v,(k1,k2)->k1));
        OrderChildPoundAuditDetailVO vo = new OrderChildPoundAuditDetailVO();
        vo.setChildNo(childNo);
        vo.setLoadImages(loadImages.stream().map(OrderChildImage::getImage).collect(Collectors.toList()));
        vo.setUnloadImages(unloadImages.stream().map(OrderChildImage::getImage).collect(Collectors.toList()));
        vo.setLoadNet(poundAuditDetail.getLoadNet());
        vo.setUnloadNet(poundAuditDetail.getUnloadNet());
        vo.setUnloadPoundNo(poundAuditDetail.getUnloadPoundNo());
        vo.setUnloadTare(poundAuditDetail.getUnloadTare());
        vo.setUnloadRough(poundAuditDetail.getUnloadRough());
        vo.setLoadRough(poundAuditDetail.getLoadRough());
        vo.setLoadTare(poundAuditDetail.getLoadTare());
        vo.setStatus(poundAuditDetail.getStatus());
        vo.setRemark(poundAuditDetail.getRemark());
        vo.setRejectType(poundAuditDetail.getRejectType());
        vo.setTruckNo(orderChild.getTruckNo());
        vo.setLoadTime(orderChild.getLoadTime()==null?null:convertLocalDateTimeToDefaultString(orderChild.getLoadTime()));
        vo.setUnloadTime(orderChild.getUnloadTime()==null?null:convertLocalDateTimeToDefaultString(orderChild.getUnloadTime()));
        vo.setSendAddress(orderChild.getSendAddress());
        vo.setReceiveAddress(orderChild.getReceiveAddress());
        vo.setLoadGrossWeight(imageTypeOcrRecognitionMap.getOrDefault(OrderChildImage.Type.LOAD.getCode(),new OcrRecognition()).getGrossWeight());
        vo.setLoadTareWeight(imageTypeOcrRecognitionMap.getOrDefault(OrderChildImage.Type.LOAD.getCode(),new OcrRecognition()).getTareWeight());
        vo.setUnloadGrossWeight(imageTypeOcrRecognitionMap.getOrDefault(OrderChildImage.Type.UNLOAD.getCode(),new OcrRecognition()).getGrossWeight());
        vo.setUnloadTareWeight(imageTypeOcrRecognitionMap.getOrDefault(OrderChildImage.Type.UNLOAD.getCode(),new OcrRecognition()).getTareWeight());

        return vo;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePoundAudit(PoundAuditParam param) {
        //运单详情
        OrderChild orderChild = orderChildDao.getByChildNo(param.getChildNo()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        BigDecimal loadNet = param.getLoadRough().subtract(param.getLoadTare());
        if (loadNet.compareTo(new BigDecimal(99)) > 0) {
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_LOAD_NET_ERROR);
        }
        if (param.getLoadTare().compareTo(param.getLoadRough()) > 0) {
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_TRACE_GT_ROUGH);
        }

        BigDecimal unLoadNet = param.getUnloadRough().subtract(param.getUnloadTare());
        if(OrderChildEnum.CANCEL_lIST.contains(orderChild.getStatus())){
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_CANCELED);
        }
        //待审核磅单
        OrderChildPoundAudit poundAuditDetail = orderChildPoundAuditDao.getPoundAuditDetail(param.getChildNo()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        if(!Objects.equals(poundAuditDetail.getStatus(),OrderChildPoundAuditEnum.Status.AUDIT.getCode())){
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_STATUS_CHANGED);
        }

        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(orderChild.getOrderGoodsNo()).orElseThrow(PerformanceResultEnum.ORDER_INVALID);

        //磅单审核对象赋值
        poundAuditDetail.setStatus(param.getStatus());
        poundAuditDetail.setRejectType(param.getRejectType());
        poundAuditDetail.setRemark(param.getRemark());
        poundAuditDetail.setId(null);
        poundAuditDetail.setCreateTime(null);
        poundAuditDetail.setModifiedTime(null);

        BigDecimal dif = loadNet.subtract(orderChild.getLoadNet());

        int type = OrderChildLogEnum.Type.POUND_AUDIT.getCode();
        if(Objects.equals(param.getStatus(), OrderChildPoundAuditEnum.Status.REJECT.getCode())){
            type = OrderChildLogEnum.Type.POUND_AUDIT_REJECT.getCode();
        }else{
            poundAuditDetail.setLoadNet(loadNet);
            poundAuditDetail.setUnloadNet(unLoadNet);
            poundAuditDetail.setLoadRough(param.getLoadRough());
            poundAuditDetail.setLoadTare(param.getLoadTare());
            poundAuditDetail.setUnloadRough(param.getUnloadRough());
            poundAuditDetail.setUnloadTare(param.getUnloadTare());
            orderChild.setLoadNet(loadNet);
            orderChild.setUnloadNet(unLoadNet);
            orderChild.setLoadRough(param.getLoadRough());
            orderChild.setLoadTare(param.getLoadTare());
            orderChild.setUnloadRough(param.getUnloadRough());
            orderChild.setUnloadTare(param.getUnloadTare());
        }
        orderChild.setWeight(orderChildWeightCalc(orderChild));
        orderChild.setFreight(orderChildFreightCalc(orderChild));

        //计算司机保证金
        PaymentDTO paymentDTO = getPaymentDTO(orderChild);
        if (Objects.nonNull(paymentDTO.getPlatformServiceFeeNew())) {
            if(paymentDTO.getPlatformServiceFeeNew().compareTo(BigDecimal.ZERO) != 0){
                orderChild.setPlatformServiceFee(paymentDTO.getPlatformServiceFeeNew());
            }
            //因为可能服务费为 0
            if(orderChild.getFreight().compareTo(BigDecimal.ZERO)<=0){
                orderChild.setPlatformServiceFee(paymentDTO.getPlatformServiceFeeNew());
            }

        }



        // 更新装车净重
        updateOrderGoodsAmountLoad(orderGoods,orderChild.getChildNo(), dif);

        //更新运单数据
        orderChild.setPoundStatus(param.getStatus());
        //磅单审核通过时间
        if (APPROVED.getCode().equals(param.getStatus())){
            orderChild.setPoundAuditTime(LocalDateTime.now());
        }
        orderChildDao.updatePoundAuditStatus(orderChild);

        //保存磅单审核数据
        orderChildPoundAuditDao.saveEntity(poundAuditDetail);

        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();
        OrderChildPoundLog poundLog = OrderChildPoundLog.builder().childNo(param.getChildNo()).status(param.getStatus()).createType(OrderChildLogEnum.CreateType.PLATFORM.getCode())
                .remark(OrderChildPoundAuditEnum.Status.getByCode(param.getStatus()).get().getMsg()).createBy(loginUserInfo.getUserNo()).createName(loginUserInfo.getUserName()).build();

        //保存磅单审核日志数据
        orderChildPoundLogDao.saveEntity(poundLog);
        //判断是否平衡冻结金额
        if(Objects.nonNull(paymentDTO.getChangeDeposit()) &&
                paymentDTO.getChangeDeposit().compareTo(BigDecimal.ZERO) !=0){
            paymentChangePlatformFee(orderChild.getChildNo(),paymentDTO.getChangeDeposit(),paymentDTO.getPlatformServiceFeeNew());
        }
        //保存运单日志数据
        orderChildLogService.saveOrderChildLog(param.getChildNo(),type,OrderChildLogEnum.Type.getByCode(type).isPresent() ? OrderChildLogEnum.Type.getByCode(type).get().getMsg() :"",
                OrderChildLogEnum.CreateType.PLATFORM.getCode(), loginUserInfo.getUserNo(),loginUserInfo.getUserName());

        orderChildPostService.orderChildPoundAudit(orderChild, poundAuditDetail);
    }

    /***
     * 平衡司机冻结保证金
     */
    public void paymentChangePlatformFee(String childNo,BigDecimal changeDeposite,BigDecimal figureNew){
        if(changeDeposite.compareTo(BigDecimal.ZERO) !=0){
            PayPlatformFeeParam payPlatformFeeParam = new PayPlatformFeeParam();
            payPlatformFeeParam.setTradeNo(childNo);
            payPlatformFeeParam.setFigure(changeDeposite.intValue());
            payPlatformFeeParam.setFigureNew(figureNew.intValue());
            //冻结司机押金
            paymentService.paymentChangePlatformFee(payPlatformFeeParam);
        }
    }
    /**
     * 装车补偿
     */
    private void updateOrderGoodsAmountLoad(OrderGoods orderGoods,String childNo, BigDecimal dif){
        int count = orderChildDao.countValidByOrderGoodsNo(orderGoods.getOrderGoodsNo())-1;
        Integer status;
        if (count == 0){
            status = OrderGoodsStatusEnum.Status.PAYING.getCode();
        }else{
            status = OrderGoodsStatusEnum.Status.GO_TO_SEND.getCode();
        }
        orderChildService.updateOrderGoodsAmountLoad(orderGoods,childNo,dif,status);
    }

    /**
     * 运单拉运吨数计算
     */
    public BigDecimal orderChildWeightCalc(OrderChild orderChild){
            return orderChild.getUnloadNet().compareTo(orderChild.getLoadNet()) < 0? orderChild.getUnloadNet() : orderChild.getLoadNet();
    }

    /**
     * 运费计算
     */
    public BigDecimal orderChildFreightCalc(OrderChild orderChild){
        BigDecimal totalFreight = orderChild.getFreightPrice().multiply(orderChild.getWeight());
        BigDecimal dif = orderChild.getUnloadNet().subtract(orderChild.getLoadNet());
        if (dif.compareTo(BigDecimal.ZERO) < 0){
            totalFreight = totalFreight.add(orderChild.getLossPrice().multiply(dif));
        }

        return totalFreight.setScale(0, RoundingMode.HALF_UP);
    }


    /***
     * 获取最新的保证金金额和本次调增的金额
     */
    public PaymentDTO getPaymentDTO(OrderChild orderChild){
        //计算司机保证金
        BigDecimal freightPrice = orderChild.getFreightPrice();
        BigDecimal deposit = orderChild.getDeposit();
        BigDecimal platformServiceFeeRate = orderChild.getPlatformServiceFeeRate();
        BigDecimal platformServiceFee = orderChild.getPlatformServiceFee(); //平台服务费
        BigDecimal freight = orderChild.getFreight();
        //本次调整金额
        BigDecimal changeDeposit = BigDecimal.ZERO;
        //本次调整金额
        BigDecimal platformServiceFeeNew = BigDecimal.ZERO;
        log.info("运单号 {} ，原始冻结金额 {} ",orderChild.getChildNo(),platformServiceFee);
        if(Objects.isNull(platformServiceFee)){
            return   PaymentDTO.builder().changeDeposit(null).platformServiceFeeNew(null).build();
        }
        if(freight.compareTo(BigDecimal.ZERO)<=0){
            return   PaymentDTO.builder().changeDeposit(platformServiceFee.multiply(new BigDecimal("-1"))).platformServiceFeeNew(platformServiceFeeNew).build();
        }
        /**
         * 如果之前未冻结保证金，本次不调整
         * 如果 平台服务费率 为0 本次不处理
         * 如果 本次吨数为 0 本次不处理
         * 如果 本次调整金额为 0 本次不处理
         * **/
        if(Objects.nonNull(deposit) && deposit.compareTo(BigDecimal.ZERO) != 0 &&
                Objects.nonNull(platformServiceFee) && platformServiceFee.compareTo(BigDecimal.ZERO) != 0 &&
                Objects.nonNull(platformServiceFeeRate) && platformServiceFeeRate.compareTo(BigDecimal.ZERO) != 0 &&
                Objects.nonNull(freight) && freight.compareTo(BigDecimal.ZERO) != 0
        )
        {
            platformServiceFeeNew = freight
                    //平台服务费率  * 100
                    .multiply(platformServiceFeeRate).movePointLeft(2).setScale(0, RoundingMode.HALF_UP);
            changeDeposit = platformServiceFeeNew.subtract(platformServiceFee);
            log.info("运单号 {}  ,原始冻结金额 {} ,最新冻结金额 {},运费差 {}  运费价格{},费率 {}",orderChild.getChildNo(),
                    platformServiceFee,platformServiceFeeNew,changeDeposit,freightPrice,platformServiceFeeRate
            );

        }
        return   PaymentDTO.builder().changeDeposit(changeDeposit).platformServiceFeeNew(platformServiceFeeNew).build();
    }
}
