package com.clx.performance.event;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.json.JSONUtil;
import com.clx.performance.component.OrderChildLoanComponent;
import com.clx.performance.constant.RabbitKeyConstants;
import com.clx.performance.dao.loan.OrderChildLoanRetryRecordDao;
import com.clx.performance.dao.loan.OwnerLoanAccountRunningWaterRecordDao;
import com.clx.performance.dao.loan.OwnerRepaymentDao;
import com.clx.performance.dao.settle.SettlementDriverDao;
import com.clx.performance.dao.settle.SettlementDriverDetailDao;
import com.clx.performance.dao.settle.SettlementOwnerDetailDao;
import com.clx.performance.dto.OwnerLoanMqDTO;
import com.clx.performance.enums.loan.BankTradeEnum;
import com.clx.performance.enums.loan.OwnerLoanAccountRunningWaterRecordEnum;
import com.clx.performance.enums.loan.OwnerLoanRecordEnum;
import com.clx.performance.enums.loan.OwnerRePaymentEnum;
import com.clx.performance.model.OrderChild;
import com.clx.performance.model.loan.OrderChildLoanRetryRecord;
import com.clx.performance.model.loan.OwnerLoanAccount;
import com.clx.performance.model.loan.OwnerLoanAccountRunningWaterRecord;
import com.clx.performance.model.loan.OwnerRepayment;
import com.clx.performance.model.settle.SettlementDriverDetail;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.service.settle.SettlementMqService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j
@AllArgsConstructor
public class EventListenerComponent {

    private final SettlementOwnerDetailDao settlementOwnerDetailDao;

    private final SettlementDriverDetailDao settlementDriverDetailDao;

    private final OrderChildLoanRetryRecordDao orderChildLoanRetryRecordDao;

    private final OwnerRepaymentDao ownerRepaymentDao;

    private final OrderChildLoanComponent orderChildLoanComponent;

    private final SettlementMqService settlementMqService;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final SettlementDriverDao settlementDriverDao;

    private final OwnerLoanAccountRunningWaterRecordDao ownerLoanAccountRunningWaterRecordDao;

    private final RabbitTemplate rabbitTemplate;


    @Async
    @TransactionalEventListener(classes = {SettlementUpdateEvent.class},phase = TransactionPhase.AFTER_ROLLBACK,fallbackExecution = true)
    public void listen(SettlementUpdateEvent event) {
        log.info("SettlementUpdateEvent事件执行");
        SettlementOwnerDetail settlementOwnerDetail = event.getSettlementOwnerDetail();
        SettlementDriverDetail settlementDriverDetail = event.getSettlementDriverDetail();
        settlementOwnerDetailDao.updateInvoiceType(settlementOwnerDetail);
        settlementDriverDetailDao.updateInvoiceTypeAndPrepayFreightFlag(settlementDriverDetail);
        Integer ownerId = settlementOwnerDetail.getId();
        Integer driverId = settlementDriverDetail.getId();

        OrderChildLoanRetryRecord record = orderChildLoanRetryRecordDao.selectOneByOwnerIdAndDriverId(ownerId, driverId);
        if (record == null) {
            OrderChildLoanRetryRecord entity = new OrderChildLoanRetryRecord();
            entity.setSettlementOwnerId(ownerId);
            entity.setSettlementDriverId(driverId);
            entity.setOwnerUserNo(settlementOwnerDetail.getOwnerUserNo());
            log.info("当前货主结算信息{},车主结算信息：{}", JSONUtil.parse(settlementOwnerDetail), JSONUtil.parse(settlementDriverDetail));
            // 保存重试记录
            orderChildLoanRetryRecordDao.saveEntity(entity);
        }

    }

    @EventListener(classes = {OwnerRepaymentUpdateEvent.class})
    public void listen(OwnerRepaymentUpdateEvent event) {
        log.info("OwnerRepaymentUpdateEvent事件执行");
        OwnerRepayment update = new OwnerRepayment();
        update.setId(event.getId());
        update.setBeOverdue(OwnerRePaymentEnum.BeOverdue.YES.getCode());
        ownerRepaymentDao.updateEntityByKey(update);
    }

    @Async
    @TransactionalEventListener(classes = {OwnerLoanEvent.class},phase = TransactionPhase.AFTER_COMMIT,fallbackExecution = true)
    public void listen(OwnerLoanEvent event) {
        log.info("OwnerLoanEvent事件执行");
        OwnerLoanMqDTO param = event.getParam();
        SettlementOwnerDetail settlementOwnerDetail = param.getSettlementOwnerDetail();
        SettlementDriverDetail settlementDriverDetail = param.getSettlementDriverDetail();
        OrderChild orderChild = param.getOrderChild();

        try {
            //生成借款标识
            orderChildLoanComponent.childLoanConfirmAfterProcess(settlementDriverDetail, settlementOwnerDetail, orderChild);
        } catch (Exception e) {
            //未借款
            settlementDriverDetail.setLoanFlag(OwnerLoanRecordEnum.LoanFlag.NO_LOAN.getCode());
            applicationEventPublisher.publishEvent(new SettlementUpdateEvent(this, settlementDriverDetail, settlementOwnerDetail));
            log.error("处理货主借款监听器执行异常,数据为{},异常信息{}", JSONUtil.parse(param), ExceptionUtil.getMessage(e));
            throw e;
        }
        log.info("处理货主借款监听器执行成功");
        settlementOwnerDetailDao.updateInvoiceType(settlementOwnerDetail);
        settlementDriverDetailDao.updateInvoiceTypeAndPrepayFreightFlag(settlementDriverDetail);

        // 发送mq 通过开票标识
        settlementMqService.invoiceTypeSync(settlementDriverDetail.getChildNo(), settlementDriverDetail.getInvoiceType());
    }


    @EventListener(classes = {OwnerLoanFlagEvent.class})
    public void listen(OwnerLoanFlagEvent event) {
        log.info("OwnerLoanFlagEvent事件执行");
        Long loanNo = event.getLoanNo();
        List<OwnerLoanAccountRunningWaterRecord> records = ownerLoanAccountRunningWaterRecordDao.selectLoanRunningWatterRecord(loanNo);
        if (CollectionUtil.isEmpty(records)) {
            return;
        }

        Map<String, List<OwnerLoanAccountRunningWaterRecord>> listMap = records.stream().collect(Collectors.groupingBy(OwnerLoanAccountRunningWaterRecord::getChildNo));

        List<String> childNoList = new LinkedList<>();
        for (Map.Entry<String, List<OwnerLoanAccountRunningWaterRecord>> entry : listMap.entrySet()) {
            if (entry.getValue().size() == 1) {
                childNoList.add(entry.getKey());
            } else {
                log.info("当前运单:{} 存在多条运单流水记录,无法更新运单的贷款标识",entry.getKey());
            }
        }
        log.info("当前需要更新的运单数量:{}", listMap.size());

        if (CollectionUtil.isNotEmpty(childNoList)) {
            settlementDriverDetailDao.updateLoanFlagByChildNoList(childNoList);
            settlementDriverDao.updateLoanFlagByChildNoList(childNoList);
        }

    }

    @EventListener(classes = {OrderChildCancelEvent.class})
    public void listen(OrderChildCancelEvent event) {
        log.info("OrderChildCancelEvent事件执行");
        String childNo = event.getChildNo();
        log.info("需要解冻借款的的运单号:{}", childNo);

        List<OwnerLoanAccountRunningWaterRecord> runningWaterRecordList = ownerLoanAccountRunningWaterRecordDao.getListByChildNoAndRunningWaterType(childNo, OwnerLoanAccountRunningWaterRecordEnum.RunWaterType.APPROVE_FROZEN.getCode());

        if (CollectionUtil.isEmpty(runningWaterRecordList)) {
            return;
        }

        Long ownerUserNo = runningWaterRecordList.get(0).getOwnerUserNo();
        log.info("当前解冻货主：{},流水记录长度{},流水记录{}", ownerUserNo, runningWaterRecordList.size(), JSONUtil.parse(runningWaterRecordList));

        for (OwnerLoanAccountRunningWaterRecord record : runningWaterRecordList) {
            Long loanNo = record.getLoanNo();
            Integer loanType = record.getLoanType();
            String ownerUserName = record.getOwnerUserName();
            BigDecimal balance = record.getAlterationBalance();
            //解冻借款
            orderChildLoanComponent.thawOwnerLoanAccount(loanNo, loanType, ownerUserNo, ownerUserName, record.getMobile(), childNo, balance);
        }

    }

    @EventListener(classes = {OwnerLoanThawEvent.class})
    public void listen(OwnerLoanThawEvent event) {
        log.info("OwnerLoanThawEvent事件执行");
        log.info("需要解冻借款的的运单号:{}", event.getChildNo());
        Message message = MessageBuilder.withBody(event.getChildNo().getBytes()).build();


        rabbitTemplate.send(
                RabbitKeyConstants.OWNER_LOAN_EXCHANGE, RabbitKeyConstants.OWNER_LOAN_THAW_ROUTE_KEY, message
        );

    }
}
