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

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.clx.performance.dao.settle.SettlementDriverDao;
import com.clx.performance.dao.settle.SettlementDriverDetailDao;
import com.clx.performance.dao.settle.SettlementOrderChildRiskDao;
import com.clx.performance.dao.settle.SettlementOwnerDetailDao;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.ResultEnum;
import com.clx.performance.enums.settle.*;
import com.clx.performance.model.settle.SettlementDriver;
import com.clx.performance.model.settle.SettlementDriverDetail;
import com.clx.performance.model.settle.SettlementOrderChildRisk;
import com.clx.performance.model.settle.SettlementOwnerDetail;
import com.clx.performance.param.pc.carrier.PageSettlementOrderChildRiskParam;
import com.clx.performance.param.pc.owner.settle.OwnerSettlementOrderChildRiskProcessUpdateParam;
import com.clx.performance.service.settle.SettlementMqService;
import com.clx.performance.service.settle.SettlementOrderChildRiskService;
import com.clx.performance.struct.settle.SettlementOrderChildRiskStruct;
import com.clx.performance.utils.excel.ExcelData;
import com.clx.performance.utils.excel.ExcelField;
import com.clx.performance.utils.excel.ExcelSheet;
import com.clx.performance.utils.excel.ExcelUtil;
import com.clx.performance.vo.pc.carrier.settle.SettlementOrderChildRiskVO;
import com.msl.common.exception.ServiceSystemException;
import com.msl.user.data.UserSessionData;
import com.msl.user.utils.TokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

@Service
@Slf4j
public class SettlementOrderChildRiskServiceImpl implements SettlementOrderChildRiskService {

    @Autowired
    private SettlementOwnerDetailDao settlementOwnerDetailDao;
    @Autowired
    private SettlementDriverDetailDao settlementDriverDetailDao;
    @Autowired
    private SettlementOrderChildRiskDao settlementOrderChildRiskDao;
    @Autowired
    private SettlementDriverDao settlementDriverDao;
    @Autowired
    private SettlementOrderChildRiskStruct settlementOrderChildRiskStruct;

    @Autowired
    private SettlementMqService settlementMqService;

    /**
     * 更新子订单风险处理信息
     * 此方法用于处理子订单的风险流程更新，根据不同的处理方式更新相关细节，并发送消息到消息队列
     *
     * @param param 包含子订单风险处理更新参数的对象
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateRiskProcess(OwnerSettlementOrderChildRiskProcessUpdateParam param) {
        UserSessionData loginUserInfo = TokenUtil.getLoginUserInfo();

        // 获取子订单风险信息，如果不存在则抛出异常
        SettlementOrderChildRisk settlementOrderChildRisk = settlementOrderChildRiskDao.getById(param.getId()).orElseThrow(ResultEnum.DATA_NOT_FIND);
        // 检查子订单风险状态，如果已处理则抛出异常
        if (Objects.equals(settlementOrderChildRisk.getStatus(), SettlementOrderChildRiskEnum.Status.PROCESSED.getCode())) {
            throw new ServiceSystemException(PerformanceResultEnum.ORDER_CHILD_RISK_PROCESS_ERROR);
        }
        // 获取子订单详细信息，如果不存在则抛出异常
        SettlementOwnerDetail settlementOwnerDetail = settlementOwnerDetailDao
                .getByChildNo(settlementOrderChildRisk.getChildNo()).orElseThrow(ResultEnum.DATA_NOT_FIND);

        // 获取司机详细信息，如果不存在则抛出异常
        SettlementDriverDetail settlementDriverDetail = settlementDriverDetailDao
                .getByChildNo(settlementOrderChildRisk.getChildNo()).orElseThrow(PerformanceResultEnum.DATA_NOT_FIND);

        // 获取司机信息，可能为null
        SettlementDriver settlementDriver = settlementDriverDao.findByChildNo(settlementOrderChildRisk.getChildNo()).orNull();

        // 更新子订单风险状态和处理信息
        settlementOrderChildRisk.setStatus(SettlementOrderChildRiskEnum.Status.PROCESSED.getCode());
        settlementOrderChildRisk.setProcessMethod(param.getProcessMethod());
        settlementOrderChildRisk.setProcessBy(loginUserInfo.getUserName());
        settlementOrderChildRisk.setProcessTime(LocalDateTime.now());

        // 转普通单
        if (Objects.equals(param.getProcessMethod(), SettlementOrderChildRiskEnum.ProcessMethod.CONVERT_ORDINARY.getCode())) {
            // 更新子订单详细信息为普通发票类型
            settlementOwnerDetail.setInvoiceType(SettlementOwnerEnum.InvoiceType.ORDINARY.getCode());
            settlementOwnerDetail.setInvoicingCompanyId(null);
            settlementOwnerDetail.setInvoicingCompanyShorterName(null);
            settlementOwnerDetail.setInvoicingCompanyGroupCode(null);
            settlementOwnerDetail.setInvoiceTypeStatus(SettlementOwnerDetailEnum.InvoiceTypeStatus.SUCCESS.getCode());
            settlementOwnerDetail.setInvoiceTypeModifiedTime(LocalDateTime.now());
            settlementOwnerDetailDao.updateConvertOrdinary(settlementOwnerDetail);

            // 同步更新司机详细信息
            settlementDriverDetail.setInvoiceType(settlementOwnerDetail.getInvoiceType());
            settlementDriverDetail.setInvoicingCompanyId(settlementOwnerDetail.getInvoicingCompanyId());
            settlementDriverDetail.setInvoicingCompanyShorterName(settlementOwnerDetail.getInvoicingCompanyShorterName());
            settlementDriverDetail.setInvoicingCompanyGroupCode(settlementOwnerDetail.getInvoicingCompanyGroupCode());
            settlementDriverDetailDao.updateConvertOrdinary(settlementDriverDetail);

            // 更新子订单风险的发票类型
            settlementOrderChildRisk.setInvoiceType(settlementOwnerDetail.getInvoiceType());

            // 如果司机信息存在，则同步更新司机信息
            if (settlementDriver != null) {
                settlementDriver.setInvoiceType(settlementDriverDetail.getInvoiceType());
                settlementDriver.setInvoicingCompanyId(settlementDriverDetail.getInvoicingCompanyId());
                settlementDriver.setInvoicingCompanyShorterName(settlementDriverDetail.getInvoicingCompanyShorterName());
                settlementDriver.setInvoicingCompanyGroupCode(settlementDriverDetail.getInvoicingCompanyGroupCode());
                settlementDriver.setPrepayFreightFlag(settlementDriverDetail.getPrepayFreightFlag());
                settlementDriverDao.updateInvoiceCompany(settlementDriver);
            }
        }
        else {
            // 状态回滚
            // 如果司机信息存在，则回滚司机状态
            if (settlementDriver != null){
                settlementDriver.setStatus(SettlementDriverEnum.Status.DRIVER_UNCONFIRMED.getCode());
                settlementDriverDao.updatePayStatus(settlementDriver);
            }

            // 回滚司机详细信息的支付接受状态
            settlementDriverDetail.setPayAcceptStatus(SettlementDriverDetailEnum.PayAcceptStatus.INIT.getCode());
            settlementDriverDetailDao.updatePayAcceptStatus(settlementDriverDetail);
        }

        // 更新子订单风险处理信息
        settlementOrderChildRiskDao.updateProcess(settlementOrderChildRisk);

        // 发送mq (风控处理)
        // 通知风险处理完成，触发后续流程
        settlementMqService.riskProcess(settlementOrderChildRisk.getId());
    }

    @Override
    public IPage<SettlementOrderChildRiskVO> pageSettlementOrderChildRisk(
            PageSettlementOrderChildRiskParam param) {
        IPage<SettlementOrderChildRisk> result = settlementOrderChildRiskDao.pageSettlementOrderChildRisk(param);
        List<SettlementOrderChildRiskVO> list = settlementOrderChildRiskStruct.covertList(result.getRecords());
        return new Page<SettlementOrderChildRiskVO>().setRecords(list).setTotal(result.getTotal()).setPages(result.getPages());
    }

    @Override
    public SXSSFWorkbook exportSettlementOrderChildRisk(PageSettlementOrderChildRiskParam param) {
        param.setPage(1);
        param.setPageSize(1000000);
        IPage<SettlementOrderChildRiskVO> settlementDriverDetailPage = pageSettlementOrderChildRisk(param);

        List<SettlementOrderChildRiskVO> list = settlementDriverDetailPage.getRecords();

        // 组装表头
        List<ExcelField> fieldList = new ArrayList<>();
        fieldList.add(new ExcelField(0, "运单编号", "childNo", 5000));
        fieldList.add(new ExcelField(1, "车牌号", "truckNo", 5000));
        fieldList.add(new ExcelField(2, "司机名称", "driverName", 5000));
        fieldList.add(new ExcelField(3, "司机联系电话", "driverMobile", 5000));
        fieldList.add(new ExcelField(4, "货物名称", "goodsName", 5000));
        fieldList.add(new ExcelField(5, "开票标识", "invoiceType", 5000));
        fieldList.add(new ExcelField(6, "开票配置", "invoiceConfigType", 5000));
        fieldList.add(new ExcelField(7, "风控标识", "riskType", 5000));
        fieldList.add(new ExcelField(8, "风控失败原因", "riskRemark", 5000));
        fieldList.add(new ExcelField(9, "处理状态", "status", 5000));
        fieldList.add(new ExcelField(10, "处理方式", "processMethod", 5000));
        fieldList.add(new ExcelField(11, "磅单审核通过时间", "poundAuditTime", 5000));
        fieldList.add(new ExcelField(12, "创建时间", "createTime", 5000));
        fieldList.add(new ExcelField(13, "处理人", "processBy", 5000));
        fieldList.add(new ExcelField(14, "处理时间", "processTime", 5000));

        // 组装数据
        List<List<ExcelData>> dataList = new ArrayList<>();
        for (SettlementOrderChildRiskVO vo : list) {
            List<ExcelData> rowData = new ArrayList<>();
            rowData.add(new ExcelData(vo.getChildNo()));
            rowData.add(new ExcelData(vo.getTruckNo()));
            rowData.add(new ExcelData(vo.getDriverName()));
            rowData.add(new ExcelData(vo.getDriverMobile()));

            rowData.add(new ExcelData(vo.getGoodsName()));
            rowData.add(new ExcelData(vo.getInvoiceType()==null?null:SettlementOwnerEnum.InvoiceType.getMsgByCode(vo.getInvoiceType())));
            rowData.add(new ExcelData(vo.getInvoiceConfigType()==null?null:SettlementOwnerEnum.InvoiceConfigType.getMsgByCode(vo.getInvoiceConfigType())));
            rowData.add(new ExcelData(vo.getRiskType()==null?null:SettlementOrderChildRiskEnum.RiskType.getMsgByCode(vo.getRiskType())));
            rowData.add(new ExcelData(vo.getRiskRemark()));
            rowData.add(new ExcelData(vo.getStatus()==null?null:SettlementOrderChildRiskEnum.Status.getMsgByCode(vo.getStatus())));
            rowData.add(new ExcelData(vo.getProcessMethod()==null?null:SettlementOrderChildRiskEnum.ProcessMethod.getMsgByCode(vo.getProcessMethod())));
            rowData.add(new ExcelData(vo.getPoundAuditTime()));
            rowData.add(new ExcelData(vo.getCreateTime()));
            rowData.add(new ExcelData(vo.getProcessBy()));
            rowData.add(new ExcelData(vo.getProcessTime()));

            dataList.add(rowData);
        }

        ExcelSheet excelSheet = new ExcelSheet("风控异常列表", "风控异常列表", fieldList, dataList);

        //创建excel
        return ExcelUtil.create(excelSheet);
    }
}
