package com.prolog.rdc.tms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.prolog.common.util.ToolKits;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.product.core.framework.entity.UserEntity;
import com.prolog.product.core.framework.util.PlgFxUsrUtils;
import com.prolog.rdc.tms.constant.BmsConstant;
import com.prolog.rdc.tms.constant.enums.LogTypeEnum;
import com.prolog.rdc.tms.dao.mapper.BmsBillPayFeeDetailMapper;
import com.prolog.rdc.tms.dao.mapper.BmsBillPayFeeHeaderMapper;
import com.prolog.rdc.tms.dao.mapper.BmsPaySettlementDetailMapper;
import com.prolog.rdc.tms.dao.mapper.BmsPaySettlementMapper;
import com.prolog.rdc.tms.dao.mapper.LoadingBillHeadMapper;
import com.prolog.rdc.tms.dao.mapper.LogisticsContractMapper;
import com.prolog.rdc.tms.model.dto.DriverledgerBillDTO;
import com.prolog.rdc.tms.model.entity.BmsBillPayFeeDetailModel;
import com.prolog.rdc.tms.model.entity.BmsBillPayFeeHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.model.entity.BmsLogisticsContractModel;
import com.prolog.rdc.tms.model.entity.BmsPaySettlementDetailModel;
import com.prolog.rdc.tms.model.entity.BmsPaySettlementModel;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import com.prolog.rdc.tms.model.vo.settlement.driver.BmsDriverFeeSettlementVO;
import com.prolog.rdc.tms.model.vo.settlement.driver.DriverFeeSettlementPageVO;
import com.prolog.rdc.tms.proxy.MainDataProxy;
import com.prolog.rdc.tms.service.BmsBillLogService;
import com.prolog.rdc.tms.service.BmsDriverFeeSettlementService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author hongbo.pan
 * @date 2023/5/4
 */
@Service
public class BmsDriverFeeSettlementServiceImpl implements BmsDriverFeeSettlementService {

    @Autowired
    private LoadingBillHeadMapper loadingBillHeadMapper;

    @Autowired
    private ConvertorUtil convertorUtil;

    @Autowired
    private BmsBillPayFeeHeaderMapper payFeeHeaderMapper;

    @Autowired
    private BmsBillPayFeeDetailMapper payFeeDetailMapper;

    @Autowired
    private BmsPaySettlementMapper paySettlementMapper;

    @Autowired
    private BmsPaySettlementDetailMapper paySettlementDetailMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private BmsBillLogService logService;

    @Autowired
    private LogisticsContractMapper logisticsContractMapper;

    @Override
    public Page<DriverledgerBillDTO> pageForDriverSettlement(DriverFeeSettlementPageVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前用户没有操作权限");
        ToolKits.isParamNull(user.getDepts(), "当前用户没有部门权限");
        // 权限控制 仅支持自有账号
        if (!BmsConstant.USER_TYPE_ZY.equals(user.getUserType())) {
            throw new BizException("当前人员没有查询权限");
        }
        // 权限赋值
        vo.setEnterpriseId(user.getEnterpriseId());
        vo.setSettlementDepartmentTds(user.getDepts());
        // 执行查询
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<DriverledgerBillDTO> driverledgerBillDTOs = loadingBillHeadMapper.pageForDriverSettlement(vo);
        if (CollectionUtil.isNotEmpty(driverledgerBillDTOs)) {
            List<SysRefdatadModel> dicData = getDic();
            driverledgerBillDTOs.forEach(driverledgerBillDTO -> {
                driverledgerBillDTO.setFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(driverledgerBillDTO.getFeeCltType())));
                driverledgerBillDTO.setVehicleAscriptionName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE, String.valueOf(driverledgerBillDTO.getVehicleAscription())));
                driverledgerBillDTO.setVehicleTypeCategoryName(ConvertorUtil.getName(dicData, BmsConstant.VEHICLE_TYPE_CATEGORY, String.valueOf(driverledgerBillDTO.getVehicleTypeCategory())));
                driverledgerBillDTO.setSynchronousStatusName(ConvertorUtil.getName(dicData, BmsConstant.SYNCHRONOUS_STATUS, String.valueOf(driverledgerBillDTO.getSynchronousStatus())));
                driverledgerBillDTO.setCostStatusName(ConvertorUtil.getName(dicData, BmsConstant.COST_STATUS, String.valueOf(driverledgerBillDTO.getCostStatus())));
                driverledgerBillDTO.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(driverledgerBillDTO.getSettlementStatus())));
                driverledgerBillDTO.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.LOADING_BILL_STATUS, String.valueOf(driverledgerBillDTO.getStatus())));
                driverledgerBillDTO.setPayFeeCltTypeName(ConvertorUtil.getName(dicData, BmsConstant.FEE_CLT_TYPE, String.valueOf(driverledgerBillDTO.getPayFeeCltType())));
            });
        }
        return PageUtils.getPage(driverledgerBillDTOs);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void feeSettlement(BmsDriverFeeSettlementVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList = payFeeHeaderMapper.findByIds(BmsBillPayFeeHeaderModel.class, vo.getFeeIdList().toArray(), null);
        if (CollectionUtil.isNotEmpty(payFeeHeaderModelList)) {
            Map<Long, List<BmsBillPayFeeDetailModel>> payFeeDetailModelMap = getPayFeeDetailModelMap(payFeeHeaderModelList);
            List<BmsLoadingBillHeaderModel> loadingBillHeaderModelList = loadingBillHeadMapper.findByIds(BmsLoadingBillHeaderModel.class, payFeeHeaderModelList.stream().map(BmsBillPayFeeHeaderModel::getBillId).toArray(), null);
            preCheck(loadingBillHeaderModelList);
            String settlementNo = mainDataProxy.getCodeNumberByCode(BmsConstant.BMS_SHIP_BILL_SETTLEMENT_ID);
            BmsPaySettlementModel paySettlementModel = BeanUtil.copyProperties(vo, BmsPaySettlementModel.class);
            paySettlementModel.setCarrierType(BmsConstant.LINE_CARRIER_TYPE_SJ);
            paySettlementModel.setDriverId(loadingBillHeaderModelList.get(0).getDriverId());
            paySettlementModel.setDriverCode(loadingBillHeaderModelList.get(0).getDriverCode());
            paySettlementModel.setDriverName(loadingBillHeaderModelList.get(0).getDriverName());
            paySettlementModel.setDriverPhoneNumber(loadingBillHeaderModelList.get(0).getDriverPhoneNumber());
            paySettlementModel.setVehiclePlateNumber(loadingBillHeaderModelList.get(0).getVehiclePlateNumber());
            paySettlementModel.setSettlementNo(settlementNo);
            paySettlementModel.setPayFeeType(2);
            paySettlementModel.setStatus(0);
            paySettlementModel.setTax(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getTax).reduce(BigDecimal.ZERO, NumberUtil::add));
            paySettlementModel.setNoTaxAmt(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getNoTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
            paySettlementModel.setTaxAmt(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
            paySettlementModel.setCreateperson(user.getNickname());
            paySettlementModel.setCreatetime(DateUtil.date());
            paySettlementModel.setUpdateperson(user.getNickname());
            paySettlementModel.setUpdatetime(DateUtil.date());
            paySettlementModel.setEnterpriseId(user.getEnterpriseId());
            paySettlementModel.setEnterpriseName(user.getEnterpriseName());
            paySettlementMapper.insertSelective(paySettlementModel);
            logService.addLog(LogTypeEnum.PAY_SETTLEMENT, paySettlementModel.getId().toString(), "新增结算单");
            batchAddPayFeeDetail(payFeeHeaderModelList, paySettlementModel, payFeeDetailModelMap);
        }
    }

    @Override
    public BmsPaySettlementModel initPaySettlement(List<Long> feeIdList) {
        List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList = payFeeHeaderMapper.findByIds(BmsBillPayFeeHeaderModel.class, feeIdList.toArray(), null);
        if (CollectionUtil.isEmpty(payFeeHeaderModelList)) {
            throw new BizException("费用不存在");
        }
        List<BmsLoadingBillHeaderModel> loadingBillHeaderModelList = loadingBillHeadMapper.findByIds(BmsLoadingBillHeaderModel.class, payFeeHeaderModelList.stream().map(BmsBillPayFeeHeaderModel::getBillId).toArray(), null);
        preCheck(loadingBillHeaderModelList);
        Map<Long, List<BmsBillPayFeeDetailModel>> payFeeDetailModelMap = getPayFeeDetailModelMap(payFeeHeaderModelList);
        BmsLoadingBillHeaderModel loadingBillHeaderModel = loadingBillHeaderModelList.get(0);
        BmsPaySettlementModel paySettlementModel = new BmsPaySettlementModel();
        paySettlementModel.setSettlementCompany(loadingBillHeaderModel.getSettlementDepartment());
        paySettlementModel.setSettlementCompanyId(NumberUtil.parseLong(loadingBillHeaderModel.getSettlementDepartmentId()));
        paySettlementModel.setSettlementCompanyCode(loadingBillHeaderModel.getSettlementDepartmentCode());
        paySettlementModel.setSettlementDepartment(loadingBillHeaderModel.getSettlementDepartment());
        paySettlementModel.setSettlementDepartmentId(loadingBillHeaderModel.getSettlementDepartmentId());
        paySettlementModel.setSettlementDepartmentCode(loadingBillHeaderModel.getSettlementDepartmentCode());
        paySettlementModel.setCarrierId(loadingBillHeaderModel.getCarrierId());
        paySettlementModel.setCarrierCode(loadingBillHeaderModel.getCarrierCode());
        paySettlementModel.setCarrierName(loadingBillHeaderModel.getCarrierName());
        paySettlementModel.setDriverId(loadingBillHeaderModel.getDriverId());
        paySettlementModel.setDriverCode(loadingBillHeaderModel.getDriverCode());
        paySettlementModel.setDriverName(loadingBillHeaderModel.getDriverName());
        paySettlementModel.setDriverPhoneNumber(loadingBillHeaderModel.getDriverPhoneNumber());
        paySettlementModel.setVehiclePlateNumber(loadingBillHeaderModel.getVehiclePlateNumber());
        paySettlementModel.setTax(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getTax).reduce(BigDecimal.ZERO, NumberUtil::add));
        paySettlementModel.setNoTaxAmt(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getNoTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
        paySettlementModel.setTaxAmt(payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getTaxAmt).reduce(BigDecimal.ZERO, NumberUtil::add));
        List<String> taxPoint = payFeeDetailModelMap.values().stream().flatMap(List::stream).map(BmsBillPayFeeDetailModel::getTaxPoint).distinct().collect(Collectors.toList());
        if (taxPoint.size() == 1) {
            paySettlementModel.setTaxPoint(taxPoint.get(0));
        }
        Criteria criteria = Criteria.forClass(BmsLogisticsContractModel.class);
        Restriction r1 = Restrictions.in(BmsLogisticsContractModel::getContractName, payFeeHeaderModelList.stream().map(BmsBillPayFeeHeaderModel::getCostContract).distinct().collect(Collectors.toList()));
        Restriction r2 = Restrictions.eq(BmsLogisticsContractModel::getEnterpriseId, loadingBillHeaderModel.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsLogisticsContractModel> contractModelList = logisticsContractMapper.findByCriteria(criteria);
        List<Integer> settlementType = contractModelList.stream().map(BmsLogisticsContractModel::getSettlementType).distinct().collect(Collectors.toList());
        if (settlementType.size() == 1) {
            paySettlementModel.setSettlementCycle(settlementType.get(0).toString());
        }
        return paySettlementModel;
    }

    /**
     * 派车单翻译数据字典
     */
    private List<SysRefdatadModel> getDic() {
        return convertorUtil.getDictionary(new String[] {
                // 核算状态
                BmsConstant.SETTLEMENT_STATUS,
                // 计费状态
                BmsConstant.COST_STATUS,
                // 同步状态
                BmsConstant.SYNCHRONOUS_STATUS,
                // 车辆类别
                BmsConstant.VEHICLE_TYPE_CATEGORY,
                // 车辆类型
                BmsConstant.VEHICLE_TYPE,
                // 费用计算类型
                BmsConstant.FEE_CLT_TYPE,
                // 装车单状态
                BmsConstant.LOADING_BILL_STATUS });
    }

    /**
     * getPayFeeDetailModelMap
     * @param payFeeHeaderModelList
     * @return
     */
    private Map<Long, List<BmsBillPayFeeDetailModel>> getPayFeeDetailModelMap(List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        Criteria criteria = Criteria.forClass(BmsBillPayFeeDetailModel.class);
        Restriction r1 = Restrictions.in(BmsBillPayFeeDetailModel::getBillId, payFeeHeaderModelList.stream().map(BmsBillPayFeeHeaderModel::getBillId).collect(Collectors.toList()));
        Restriction r2 = Restrictions.in(BmsBillPayFeeDetailModel::getBillNo, payFeeHeaderModelList.stream().map(BmsBillPayFeeHeaderModel::getBillNo).collect(Collectors.toList()));
        Restriction r3 = Restrictions.eq(BmsBillPayFeeDetailModel::getEnterpriseId, user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2, r3));
        List<BmsBillPayFeeDetailModel> payFeeDetailModelList = payFeeDetailMapper.findByCriteria(criteria);
        return payFeeDetailModelList.stream().collect(Collectors.groupingBy(BmsBillPayFeeDetailModel::getBillId));
    }

    /**
     * batchAddPayFeeDetail
     * @param payFeeHeaderModelList
     * @param paySettlementModel
     * @param payFeeDetailModelMap
     */
    private void batchAddPayFeeDetail(List<BmsBillPayFeeHeaderModel> payFeeHeaderModelList, BmsPaySettlementModel paySettlementModel, Map<Long, List<BmsBillPayFeeDetailModel>> payFeeDetailModelMap) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        payFeeHeaderModelList.stream().forEach(payFeeHeaderModel -> {
            payFeeHeaderModel.setCheckStatus(BmsConstant.CHECK_STATUS_3);
            payFeeHeaderModel.setUpdateperson(user.getNickname());
            payFeeHeaderModel.setUpdatetime(DateUtil.date());
            payFeeHeaderMapper.update(payFeeHeaderModel);
            logService.addLog(LogTypeEnum.PAY_FEE, payFeeHeaderModel.getId().toString(), "加入结算单，结算单号" + paySettlementModel.getSettlementNo());
            List<BmsBillPayFeeDetailModel> billPayFeeDetailModelList = payFeeDetailModelMap.get(payFeeHeaderModel.getBillId());
            if (CollectionUtil.isNotEmpty(billPayFeeDetailModelList)) {
                billPayFeeDetailModelList.forEach(bmsBillPayFeeDetailModel -> {
                    BmsPaySettlementDetailModel paySettlementDetailModel = new BmsPaySettlementDetailModel();
                    paySettlementDetailModel.setSettlementId(paySettlementModel.getId());
                    paySettlementDetailModel.setFeeId(payFeeHeaderModel.getId());
                    paySettlementDetailModel.setFeeDetailId(bmsBillPayFeeDetailModel.getId());
                    paySettlementDetailModel.setExpenseNo(bmsBillPayFeeDetailModel.getExpenseNo());
                    paySettlementDetailModel.setBillId(payFeeHeaderModel.getBillId());
                    paySettlementDetailModel.setBillNo(payFeeHeaderModel.getBillNo());
                    paySettlementDetailModel.setBillType(20);
                    paySettlementDetailModel.setPayFeeType(2);
                    paySettlementDetailModel.setTaxPoint(bmsBillPayFeeDetailModel.getTaxPoint());
                    paySettlementDetailModel.setTaxAmt(bmsBillPayFeeDetailModel.getTaxAmt());
                    paySettlementDetailModel.setNoTaxAmt(bmsBillPayFeeDetailModel.getNoTaxAmt());
                    paySettlementDetailModel.setTax(bmsBillPayFeeDetailModel.getTax());
                    paySettlementDetailModel.setCreateperson(user.getNickname());
                    paySettlementDetailModel.setCreatetime(DateUtil.date());
                    paySettlementDetailModel.setUpdateperson(user.getNickname());
                    paySettlementDetailModel.setUpdatetime(DateUtil.date());
                    paySettlementDetailModel.setEnterpriseId(user.getEnterpriseId());
                    paySettlementDetailModel.setEnterpriseName(user.getEnterpriseName());
                    paySettlementDetailMapper.save(paySettlementDetailModel);
                });
            }
        });
    }

    /**
     * preCheck
     * @param loadingBillHeaderModelList
     */
    private void preCheck(List<BmsLoadingBillHeaderModel> loadingBillHeaderModelList) {
        if (CollectionUtil.isEmpty(loadingBillHeaderModelList)) {
            throw new BizException("派车单不存在");
        }
        if (loadingBillHeaderModelList.stream().map(BmsLoadingBillHeaderModel::getSettlementDepartmentId).distinct().count() > 1) {
            throw new BizException("结算部门不相同");
        }
        if (loadingBillHeaderModelList.stream().map(BmsLoadingBillHeaderModel::getDriverName).distinct().count() > 1) {
            throw new BizException("司机姓名不相同");
        }
        if (loadingBillHeaderModelList.stream().map(BmsLoadingBillHeaderModel::getDriverPhoneNumber).distinct().count() > 1) {
            throw new BizException("司机手机号不相同");
        }
        if (loadingBillHeaderModelList.stream().map(BmsLoadingBillHeaderModel::getVehiclePlateNumber).distinct().count() > 1) {
            throw new BizException("车牌号不相同");
        }
    }
}
