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

import com.clx.performance.config.MslPaymentConfig;
import com.clx.performance.constant.RedissonConstants;
import com.clx.performance.dao.OrderChildDao;
import com.clx.performance.dao.OrderGoodsDao;
import com.clx.performance.dao.settle.SettlementDriverDao;
import com.clx.performance.dao.settle.SettlementDriverDetailDao;
import com.clx.performance.dao.settle.SettlementOwnerDao;
import com.clx.performance.dao.settle.SettlementOwnerDetailDao;
import com.clx.performance.enums.OrderChildEnum;
import com.clx.performance.enums.OrderChildLogEnum;
import com.clx.performance.enums.PayRemarkEnum;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.settle.SettlementDriverEnum;
import com.clx.performance.enums.settle.SettlementLogEnum;
import com.clx.performance.enums.settle.SettlementOwnerEnum;
import com.clx.performance.enums.settle.SettlementPlatformEnum;
import com.clx.performance.extranal.user.DriverService;
import com.clx.performance.extranal.user.OwnerInfoService;
import com.clx.performance.feign.TransportFeignService;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.OrderGoods;
import com.clx.performance.model.settle.SettlementDriver;
import com.clx.performance.model.settle.SettlementDriverDetail;
import com.clx.performance.model.settle.SettlementOwner;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.param.pc.payment.PayParam;
import com.clx.performance.service.OrderChildLogService;
import com.clx.performance.service.PaymentService;
import com.clx.performance.service.impl.UniqueOrderNumService;
import com.clx.performance.service.settle.OrderChildSyncTransportRecordService;
import com.clx.performance.service.settle.SettlementLogService;
import com.clx.performance.service.settle.SettlementMqHandlerService;
import com.clx.performance.service.settle.SettlementService;
import com.clx.performance.utils.LocalDateTimeUtils;
import com.clx.performance.utils.RedisUtil;
import com.clx.performance.vo.mq.SettlementDetailAddMqParam;
import com.clx.performance.vo.mq.SettlementDetailInvoiceTypeSyncMqParam;
import com.clx.user.vo.feign.DriverInfoFeignVo;
import com.clx.user.vo.feign.OwnerInfoFeignVO;
import com.msl.common.enums.ResultCodeEnum;
import com.msl.common.exception.ServiceSystemException;
import com.msl.common.result.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Slf4j
@Service
public class SettlementMqHandlerServiceImpl implements SettlementMqHandlerService {

    @Autowired
    private SettlementOwnerDetailDao settlementOwnerDetailDao;
    @Autowired
    private SettlementDriverDetailDao settlementDriverDetailDao;
    @Autowired
    private SettlementOwnerDao settlementOwnerDao;
    @Autowired
    private SettlementDriverDao settlementDriverDao;

    @Autowired
    private OwnerInfoService ownerInfoService;

    @Autowired
    private UniqueOrderNumService uniqueOrderNumService;

    @Autowired
    private SettlementService settlementService;

    @Autowired
    private  SettlementLogService settlementLogService;

    @Autowired
    private DriverService driverService;

    @Autowired
    private PaymentService paymentService;


    @Autowired
    private OrderGoodsDao orderGoodsDao;

    @Autowired
    private MslPaymentConfig mslPaymentConfig;

    @Autowired
    private OrderChildDao orderChildDao;

    @Autowired
    private OrderChildLogService orderChildLogService;

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    private OrderChildSyncTransportRecordService childSyncTransportRecordService;




    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementDetailInvoiceTypeSync(SettlementDetailInvoiceTypeSyncMqParam mq) {
        SettlementOwnerDetail settlementOwnerDetail = settlementOwnerDetailDao.getByChildNo(mq.getChildNo()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        SettlementDriverDetail settlementDriverDetail = settlementDriverDetailDao.getByChildNo(mq.getChildNo()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        String settlementNo = null ;
        SettlementOwner settlementOwner = null;

        OwnerInfoFeignVO ownerInfo = ownerInfoService.getOwnerInfo(settlementOwnerDetail.getOwnerUserNo());

        OrderGoods orderGoods = orderGoodsDao.getByOrderGoodsNo(settlementOwnerDetail.getOrderGoodsNo()).get();
        if (Objects.equals(orderGoods.getSettlementAccountPeriod(),2)){  //月结
            log.info("月结初始化货主结算单");
            LocalDateTime settlementPeriodTime = LocalDateTimeUtils.getBeginMonthDate();
            settlementOwner = settlementOwnerDao.selectUnlockOfSettlementPeriodMonth(settlementOwnerDetail.getOrderNo(), settlementPeriodTime, settlementOwnerDetail.getInvoiceType()).orNull();
            if (settlementOwner == null){   // 月结初始化
                settlementNo = settlementPeriodMonthInit(settlementOwnerDetail, settlementPeriodTime,ownerInfo);
            }
            else {  // 月结更新
                settlementPeriodMonthUpdate(settlementOwner, settlementOwnerDetail);
                settlementNo = settlementOwner.getSettlementNo();
            }
        }
        else {
            log.info("月结初始化货主结算单");

            settlementOwner = settlementOwnerDao.selectUnlockOfSettlementPeriodImmediate(settlementOwnerDetail.getOrderNo(), settlementOwnerDetail.getInvoiceType()).orNull();
            if (settlementOwner == null){   // 拉运完成初始化
                settlementNo = settlementPeriodImmediateInit(settlementOwnerDetail,ownerInfo);
            }
            else {  // 拉运完成更新
                settlementPeriodImmediateUpdate(settlementOwner, settlementOwnerDetail);
                settlementNo = settlementOwner.getSettlementNo();
            }
        }

        //生成车主结算单
        settlementDriverSave(settlementDriverDetail,settlementNo);
        //车主结算单自动支付
        if (!settlementDriverDetail.getInvoiceType().equals(SettlementOwnerEnum.InvoiceType.ONLINE.getCode())) {
            paySettlementDriver(settlementDriverDetail);
        } else {
            if (settlementDriverDetail.getPrepayFreightFlag().equals(SettlementDriverEnum.PrepayFreightFlag.PAYED.getCode())
            && settlementDriverDetail.getPrepayFreight().compareTo(BigDecimal.ZERO) > 0) {
                settlementDriverDetail.setSettlementNo(settlementNo);
                //插入同步网络货运待支付记录
                childSyncTransportRecordService.addOrderChildSyncTransportRecord(settlementDriverDetail);
            }
        }

        // 更新结算单
        settlementOwnerDetail.setSettlementNo(settlementNo);
        settlementDriverDetail.setSettlementNo(settlementNo);
        settlementOwnerDetailDao.updateSettlementNo(settlementOwnerDetail);
        settlementDriverDetailDao.updateSettlementNo(settlementDriverDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void settlementDetailAdd(SettlementDetailAddMqParam mq) {
        SettlementOwnerDetail settlementOwnerDetail = settlementOwnerDetailDao.getEntityByKey(mq.getSettlementOwnerDetailId()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);
        //SettlementDriverDetail settlementDriverDetail = settlementDriverDetailDao.getEntityByKey(mq.getSettlementDriverDetailId()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        settlementService.updateSettlementDetailInvoiceType(settlementOwnerDetail.getChildNo(), SettlementOwnerEnum.InvoiceType.ORDINARY.getCode());
    }

    private void settlementDriverSave(SettlementDriverDetail detail,String settlementNo){
        SettlementDriver settlementDriver = new SettlementDriver();
        settlementDriver.setDriverUserNo(detail.getDriverUserNo());
        settlementDriver.setDriverName(detail.getDriverName());
        settlementDriver.setSettlementNo(settlementNo);
        settlementDriver.setChildNo(detail.getChildNo());
        settlementDriver.setOrderGoodsNo(detail.getOrderGoodsNo());
        settlementDriver.setOrderNo(detail.getOrderNo());
        settlementDriver.setGoodsId(detail.getGoodsId());
        settlementDriver.setGoodsName(detail.getGoodsName());
        settlementDriver.setTruckNo(detail.getTruckNo());
        settlementDriver.setFreightPrice(detail.getFreightPrice());
        settlementDriver.setWeight(detail.getWeight());
        settlementDriver.setFreight(detail.getFreight());
        settlementDriver.setLossPrice(detail.getLossPrice());
        settlementDriver.setLossWeight(detail.getLossWeight());
        settlementDriver.setLossFreight(detail.getLossFreight());
        settlementDriver.setPrepayFreightFlag(detail.getPrepayFreightFlag());
        settlementDriver.setSettlementFreight(detail.getSettlementFreight());
        settlementDriver.setInvoiceType(detail.getInvoiceType());
        settlementDriver.setSettlementPlatform(detail.getInvoiceType() == 1 ?
                        String.valueOf(SettlementPlatformEnum.Platform.WY.getCode()):
                String.valueOf(SettlementPlatformEnum.Platform.MSL.getCode()));
        if (settlementDriver.getInvoiceType().equals(SettlementOwnerEnum.InvoiceType.ONLINE.getCode())) {
            settlementDriver.setStatus(SettlementDriverEnum.Status.SETTLED.getCode());
        } else {
            settlementDriver.setStatus(SettlementDriverEnum.Status.WAIT_SETTLEMENT.getCode());
        }



        settlementDriverDao.saveEntity(settlementDriver);
    }

    public void settlementDriverNotify(String childNo,Integer payType,String payErrorMsg){

        //运单状态修改为完成
        OrderChild orderChild = orderChildDao.getByChildNo(childNo).orElseThrow(PerformanceResultEnum.ORDER_CHILD_NO_FOUND);
        SettlementDriver settlementDriver = settlementDriverDao.getByChildNo(childNo).orElseThrow(PerformanceResultEnum.ORDER_CHILD_NO_FOUND);

        if(1 == payType){
            orderChild.setStatus(OrderChildEnum.Status.COMPLETE.getCode());
            orderChild.setSettleTime(LocalDateTime.now());
            orderChild.setFinishTime(orderChild.getSettleTime());
            orderChildDao.updateSettlement(orderChild);

            settlementDriver.setStatus(SettlementDriverEnum.Status.SETTLED.getCode());
            settlementDriverDao.updateEntityByKey(settlementDriver);

            // 日志
            orderChildLogService.saveDriverOrderChildLog(childNo, OrderChildLogEnum.Type.COMPLETE.getCode(),
                    OrderChildLogEnum.Type.COMPLETE.getMsg(), 0L, "系统");
        }else{
            settlementDriver.setPayErrorMsg(payErrorMsg);
            settlementDriverDao.updateEntityByKey(settlementDriver);
        }

    }

    /**
     * 车主结算单自动支付
     */
    public String paySettlementDriver(SettlementDriverDetail detail){
        String uuid = UUID.randomUUID().toString();
        String key = RedissonConstants.SETTLEMENT_OWNER_BATCH_PAY_ID_LOCK + detail.getId();
        try{
            boolean flag = redisUtil.lock(key, uuid,180);
            if(!flag){
                return "获取支付锁失败，操作频繁，请稍后重试";
            }

            DriverInfoFeignVo driverInfoFeignVo = driverService.getDriverInfo(detail.getDriverUserNo()).orElseThrow(ResultCodeEnum.FAIL);
            PayParam noCheckPwd = null ;
            if(detail.getSettlementFreight().compareTo(BigDecimal.ZERO) > 0){
                noCheckPwd = PayParam.builder().from(mslPaymentConfig.getTransportWalletCode())
                        .to(driverInfoFeignVo.getWalletCode())
                        .figure(detail.getSettlementFreight().intValue())
                        .tradeNo(detail.getChildNo())
                        .tradeId(detail.getChildNo())
                        .pwd("noCheckPwd")
                        .remark(PayRemarkEnum.toString(PayRemarkEnum.FREIGHT_TO_OWNER.getValue()))
                        .build();
            }else{
                BigDecimal freight = detail.getSettlementFreight().abs();
                noCheckPwd = PayParam.builder().from(driverInfoFeignVo.getWalletCode())
                        .to(mslPaymentConfig.getTransportWalletCode())
                        .figure(freight.intValue())
                        .tradeNo(detail.getChildNo())
                        .tradeId(detail.getChildNo())
                        .pwd("noCheckPwd")
                        .remark(PayRemarkEnum.toString(PayRemarkEnum.FREIGHT_TO_OWNER.getValue()))
                        .build();
            }

            Result result = null;
            String msg  = null;
            try{
                result = paymentService.paymentWallet(noCheckPwd);
            }catch (Exception e){
                settlementDriverNotify(detail.getChildNo(),0,e.getMessage());
                msg = e.getMessage();
            }
            if(Objects.nonNull(result)){
                settlementDriverNotify(detail.getChildNo(),0,result.getMsg());
            }
            return msg;
        }catch (Exception e){
            log.warn("结算单支付上锁失败，结算单ID：{},异常原因:{}", detail.getId(), ExceptionUtils.getStackTrace(e));
            //解锁
            redisUtil.unlock(key,uuid);
            throw new ServiceSystemException(PerformanceResultEnum.TRY_LOCK_ERROR);
        }
    }

    /**
     * 月结初始化
     */
    private String settlementPeriodMonthInit(SettlementOwnerDetail settlementOwnerDetail, LocalDateTime settlementPeriodTime,OwnerInfoFeignVO ownerInfo){


        //获取所有detail

        SettlementOwner settlementOwner = new SettlementOwner();

        String settlementNo = settlementNoGenerate();

        settlementOwner.setSettlementNo(settlementNo);
        settlementOwner.setOwnerUserNo(settlementOwnerDetail.getOwnerUserNo());
        settlementOwner.setOwnerName(settlementOwnerDetail.getOwnerName());
        settlementOwner.setOrderNo(settlementOwnerDetail.getOrderNo());

        settlementOwner.setSettlementPeriodType(SettlementOwnerEnum.SettlementPeriodType.MONTH.getCode());
        settlementOwner.setSettlementPeriodTime(settlementPeriodTime);

        settlementOwner.setWeight(settlementOwnerDetail.getWeight());
        settlementOwner.setFreight(settlementOwnerDetail.getFreight());
        settlementOwner.setLossWeight(settlementOwnerDetail.getLossWeight());
        settlementOwner.setLossFreight(settlementOwnerDetail.getLossFreight());
        settlementOwner.setSettlementFreight(settlementOwnerDetail.getSettlementFreight());

        settlementOwner.setInvoiceType(settlementOwnerDetail.getInvoiceType());
        settlementOwner.setInvoiceFreight(settlementOwnerDetail.getInvoiceFreight());

        settlementOwner.setPrepayFreight(settlementOwnerDetail.getPrepayFreight());
        settlementOwner.setStatus(SettlementOwnerEnum.Status.TO_BE_LOCKED.getCode());
        settlementOwner.setInvoiceStatus(SettlementOwnerEnum.InvoiceStatus.NOT_INVOICE.getCode());

        settlementOwner.setCompanyName(ownerInfo.getCompanyName());
        settlementOwner.setCompanyTaxCode(ownerInfo.getCompanyTaxCode());
        settlementOwner.setCompanyAddress(ownerInfo.getCompanyAddress());
        settlementOwner.setCompanyMobile(ownerInfo.getCompanyTelephone());
        settlementOwner.setCompanyBankNo(ownerInfo.getCompanyBankAccount());
        settlementOwner.setCompanyBankName(ownerInfo.getCompanyOpenBank());

        settlementOwner.setCompanyContact(ownerInfo.getContactsName());
        settlementOwner.setCompanyContactMobile(ownerInfo.getContactsTelephone());
        settlementOwner.setCompanyContactAddress(ownerInfo.getContactsAddress());
        settlementOwner.setSettlementWay(settlementOwnerDetail.getSettlementWay());
        settlementOwnerDao.saveEntity(settlementOwner);

        //保存结算单日志----创建结算单
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.CREATE_SETTLEMENT.getCode(),SettlementLogEnum.Type.CREATE_SETTLEMENT.getMsg(),
                OrderChildLogEnum.CreateType.PLATFORM.getCode(),0L,"系统");

        return settlementNo;
    }

    /**
     * 月结更新
     */
    private void settlementPeriodMonthUpdate(SettlementOwner settlementOwner, SettlementOwnerDetail settlementOwnerDetail){

        settlementOwner.setWeight(settlementOwnerDetail.getWeight());
        settlementOwner.setFreight(settlementOwnerDetail.getFreight());
        settlementOwner.setLossWeight(settlementOwnerDetail.getLossWeight());
        settlementOwner.setLossFreight(settlementOwnerDetail.getLossFreight());
        settlementOwner.setPrepayFreight(settlementOwnerDetail.getPrepayFreight());
        settlementOwner.setSettlementFreight(settlementOwnerDetail.getSettlementFreight());
        settlementOwner.setInvoiceFreight(settlementOwnerDetail.getInvoiceFreight());

        List<SettlementOwnerDetail> details = settlementOwnerDetailDao.getBySettlementNo(settlementOwner.getSettlementNo());

        details.forEach(item->{
            settlementOwner.setWeight(settlementOwner.getWeight().add(item.getWeight()));
            settlementOwner.setFreight(settlementOwner.getFreight().add(item.getFreight()));
            settlementOwner.setLossWeight(settlementOwner.getLossWeight().add(item.getLossWeight()));
            settlementOwner.setLossFreight(settlementOwner.getLossFreight().add(item.getLossFreight()));
            settlementOwner.setPrepayFreight(settlementOwner.getPrepayFreight().add(item.getPrepayFreight()));
            settlementOwner.setSettlementFreight(settlementOwner.getSettlementFreight().add(item.getSettlementFreight()));
            settlementOwner.setInvoiceFreight(settlementOwner.getInvoiceFreight().add(item.getInvoiceFreight()));
        });

        settlementOwnerDao.updateSettlementPeriodMonth(settlementOwner);
    }

    /**
     * 拉运完成结 初始化
     */
    private String settlementPeriodImmediateInit(SettlementOwnerDetail settlementOwnerDetail,OwnerInfoFeignVO ownerInfo){
        SettlementOwner settlementOwner = new SettlementOwner();

        String settlementNo = settlementNoGenerate();

        settlementOwner.setSettlementNo(settlementNo);
        settlementOwner.setOwnerUserNo(settlementOwnerDetail.getOwnerUserNo());
        settlementOwner.setOwnerName(settlementOwnerDetail.getOwnerName());
        settlementOwner.setOrderNo(settlementOwnerDetail.getOrderNo());

        settlementOwner.setSettlementPeriodType(SettlementOwnerEnum.SettlementPeriodType.IMMEDIATE.getCode());

        settlementOwner.setWeight(settlementOwnerDetail.getWeight());
        settlementOwner.setFreight(settlementOwnerDetail.getFreight());
        settlementOwner.setLossWeight(settlementOwnerDetail.getLossWeight());
        settlementOwner.setLossFreight(settlementOwnerDetail.getLossFreight());
        settlementOwner.setSettlementFreight(settlementOwnerDetail.getSettlementFreight());

        settlementOwner.setInvoiceType(settlementOwnerDetail.getInvoiceType());
        settlementOwner.setInvoiceFreight(settlementOwnerDetail.getInvoiceFreight());

        settlementOwner.setPrepayFreight(settlementOwnerDetail.getPrepayFreight());
        settlementOwner.setStatus(SettlementOwnerEnum.Status.TO_BE_LOCKED.getCode());

        settlementOwner.setCompanyName(ownerInfo.getCompanyName());
        settlementOwner.setCompanyTaxCode(ownerInfo.getCompanyTaxCode());
        settlementOwner.setCompanyAddress(ownerInfo.getCompanyAddress());
        settlementOwner.setCompanyMobile(ownerInfo.getCompanyTelephone());
        settlementOwner.setCompanyBankNo(ownerInfo.getCompanyBankAccount());
        settlementOwner.setCompanyBankName(ownerInfo.getCompanyOpenBank());

        settlementOwner.setCompanyContact(ownerInfo.getContactsName());
        settlementOwner.setCompanyContactMobile(ownerInfo.getContactsTelephone());
        settlementOwner.setCompanyContactAddress(ownerInfo.getContactsAddress());
        settlementOwner.setSettlementWay(settlementOwnerDetail.getSettlementWay());
        settlementOwner.setInvoiceStatus(SettlementOwnerEnum.InvoiceStatus.NOT_INVOICE.getCode());

        settlementOwnerDao.saveEntity(settlementOwner);

        //保存结算单日志----创建结算单
        settlementLogService.saveSettlementLog(settlementNo,
                SettlementLogEnum.Type.CREATE_SETTLEMENT.getCode(),SettlementLogEnum.Type.CREATE_SETTLEMENT.getMsg(),
                OrderChildLogEnum.CreateType.PLATFORM.getCode(),0L,"系统");

        return settlementNo;
    }

    /**
     * 拉运完成结 更新
     */
    private void settlementPeriodImmediateUpdate(SettlementOwner settlementOwner,SettlementOwnerDetail settlementOwnerDetail){

        settlementOwner.setWeight(settlementOwnerDetail.getWeight());
        settlementOwner.setFreight(settlementOwnerDetail.getFreight());
        settlementOwner.setLossWeight(settlementOwnerDetail.getLossWeight());
        settlementOwner.setLossFreight(settlementOwnerDetail.getLossFreight());
        settlementOwner.setPrepayFreight(settlementOwnerDetail.getPrepayFreight());
        settlementOwner.setSettlementFreight(settlementOwnerDetail.getSettlementFreight());
        settlementOwner.setInvoiceFreight(settlementOwnerDetail.getInvoiceFreight());

        List<SettlementOwnerDetail> details = settlementOwnerDetailDao.getBySettlementNo(settlementOwner.getSettlementNo());

        details.forEach(item->{
            settlementOwner.setWeight(settlementOwner.getWeight().add(item.getWeight()));
            settlementOwner.setFreight(settlementOwner.getFreight().add(item.getFreight()));
            settlementOwner.setLossWeight(settlementOwner.getLossWeight().add(item.getLossWeight()));
            settlementOwner.setLossFreight(settlementOwner.getLossFreight().add(item.getLossFreight()));
            settlementOwner.setPrepayFreight(settlementOwner.getPrepayFreight().add(item.getPrepayFreight()));
            settlementOwner.setSettlementFreight(settlementOwner.getSettlementFreight().add(item.getSettlementFreight()));
            settlementOwner.setInvoiceFreight(settlementOwner.getInvoiceFreight().add(item.getInvoiceFreight()));
        });

        settlementOwnerDao.updateSettlementPeriodMonth(settlementOwner);
    }

    /**
     * 创建结算单号
     */
    public String settlementNoGenerate(){
        return uniqueOrderNumService.getUniqueOrderNum(com.msl.common.utils.LocalDateTimeUtils.convertLocalDateTimeToString(LocalDateTime.now(), com.msl.common.utils.LocalDateTimeUtils.DATE_DAY));
    }

}
