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

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.prolog.framework.common.message.RestMessage;
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.dao.mapper.*;
import com.prolog.rdc.tms.model.dto.ShipBillDTO;
import com.prolog.rdc.tms.model.dto.ShipBillDetailDTO;
import com.prolog.rdc.tms.model.dto.ShipBillFeeListDTO;
import com.prolog.rdc.tms.model.dto.SySParameterDTO;
import com.prolog.rdc.tms.model.entity.*;
import com.prolog.rdc.tms.model.vo.SettlementOrderVO;
import com.prolog.rdc.tms.model.vo.ShipBillQueryVO;
import com.prolog.rdc.tms.rmi.feign.MaindataFeign;
import com.prolog.rdc.tms.service.SettlementManagementService;
import com.prolog.rdc.tms.util.ConvertorUtil;
import org.apache.ibatis.plugin.PluginException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service
public class SettlementManagementServiceImpl implements SettlementManagementService {

    @Autowired
    private ShipBillHeadMapper shipBillHeadMapper;
    @Autowired
    private BmsShipbillSettlementMapper settlementMapper;
    @Autowired
    private MaindataFeign maindataTmsResource;
    @Autowired
    private BmsLogOperationMapper logOperationMapper;
    @Autowired
    private ConvertorUtil convertorUtil;
    @Autowired
    private ShipBillDetailMapper shipBillDetailMapper;
    @Autowired
    private BmsShipbillSettlementDetailMapper settlementDetailMapper;
    @Autowired
    private ShipBillFeeDetailMapper feeDetailMapper;
    @Autowired
    private LogisticsContractMapper logisticsContractMapper;

    @Override
    public Page<ShipBillFeeListDTO> findList(ShipBillQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        if (!user.getUserType().equals(BmsConstant.USER_TYPE_ZY)) {
            throw new PluginException("仅支持自有账号查询");
        }
        // 判断是否为部门权限
        RestMessage<SySParameterDTO> parameterModel = maindataTmsResource.queryParameter();
        if (!parameterModel.isSuccess() || ObjectUtil.isEmpty(parameterModel.getData())) {
            throw new PluginException("获取系统参数异常");
        }
        Integer isReconciliation = parameterModel.getData().getIsReconciliation();
        if (isReconciliation == 1) {
            vo.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_3);
        } else {
            vo.setSettlementStatus(BmsConstant.SETTLEMENT_STATUS_0);
        }
        List<ShipBillFeeListDTO> feeList;
        vo.setUserType(user.getUserType());
        if (user.getOwnedAllDataAuthFlag().equals(BmsConstant.USER_DEPARTMENT_AUTH_Y)) {
            vo.setDepartmentIds(user.getDepts().toArray(new String[0]));
            vo.setIsDept(BmsConstant.IS_DEPT_YES);
        } else {
            vo.setIsDept(BmsConstant.IS_DEPT_NO);
            vo.setDepartmentIds(user.getDepts().toArray(new String[0]));
            vo.setBranchIds(user.getWarehouses());
            vo.setCargoOwnerIds(user.getConsignors());
            // 客户
            vo.setCustomers(user.getCustomers());
            // 供应商
            vo.setSuppliers(user.getSuppliers());
        }
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        feeList = shipBillHeadMapper.findFeeListForStatus(vo, user.getEnterpriseId());

        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.SHIPBILL_STATUS, // 运单状态
                BmsConstant.SHIPPER_TYPE, // 运输状态
                BmsConstant.ABNORMAL_STATUS, // 异常状态
                BmsConstant.ORDER_TYPE, // 订单类型
                BmsConstant.CONSIGNEE_TYPE, // 收货方类型
                BmsConstant.ORDER_BUSINESS_TYPE, // 订单业务类型
                BmsConstant.SOURCE, // 来源
                BmsConstant.EXPENSE_STATUS, // 费用状态
                BmsConstant.CHECK_STATUS, // 结算状态
                BmsConstant.SETTLEMENT_STATUS,
                BmsConstant.TEMPERATURE_REQUIREMENT// 温度要求
        });

        for (ShipBillFeeListDTO shipBillFeeListDTO : feeList) {
            // 查询结算周期
            String costContract = shipBillFeeListDTO.getCostContract();
            Criteria criteria = Criteria.forClass(BmsLogisticsContractModel.class);
            Restriction r1 = Restrictions.eq("contractName", costContract);
            Restriction r2 = Restrictions.eq("status", 1);
            criteria.setRestriction(Restrictions.and(r1, r2));
            List<BmsLogisticsContractModel> contractModels = logisticsContractMapper.findByCriteria(criteria);
            if (ObjectUtil.isNotEmpty(contractModels)) {
                BmsLogisticsContractModel contractModel = contractModels.get(0);
                Integer settlementType = contractModel.getSettlementType();
                shipBillFeeListDTO.setSettlementCycle(settlementType);
            }
            shipBillFeeListDTO.setBillingSourceName(shipBillFeeListDTO.getBillingSource() == 1 ? "价格表生成" : "手工录入");
            shipBillFeeListDTO.setCheckStatusName(ConvertorUtil.getName(dicData, BmsConstant.CHECK_STATUS, String.valueOf(shipBillFeeListDTO.getCheckStatus())));
            shipBillFeeListDTO.setExpenseMemo(shipBillFeeListDTO.getMemo());
            shipBillFeeListDTO.setOrderTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_TYPE, String.valueOf(shipBillFeeListDTO.getOrderType())));
            shipBillFeeListDTO.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_BUSINESS_TYPE, String.valueOf(shipBillFeeListDTO.getOrderBusinessType())));
            shipBillFeeListDTO.setTemperatureRequirementName(ConvertorUtil.getName(dicData, BmsConstant.TEMPERATURE_REQUIREMENT, String.valueOf(shipBillFeeListDTO.getTemperatureRequirement())));
            shipBillFeeListDTO.setShipperTypeName(ConvertorUtil.getName(dicData, BmsConstant.SHIPPER_TYPE, String.valueOf(shipBillFeeListDTO.getShipperType())));
            shipBillFeeListDTO.setConsigneeTypeName(ConvertorUtil.getName(dicData, BmsConstant.CONSIGNEE_TYPE, String.valueOf(shipBillFeeListDTO.getConsigneeType())));
            shipBillFeeListDTO.setDeliveryMethodTypeName(shipBillFeeListDTO.getDeliveryMethodType() == 1 ? "配送" : "自提");
            shipBillFeeListDTO.setTransportTypeName(shipBillFeeListDTO.getTransportType() == 1 ? "整车" : "零担");
            shipBillFeeListDTO.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(shipBillFeeListDTO.getStatus())));
            shipBillFeeListDTO.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(shipBillFeeListDTO.getSource())));
            shipBillFeeListDTO.setSettlementStatusName(ConvertorUtil.getName(dicData, BmsConstant.SETTLEMENT_STATUS, String.valueOf(shipBillFeeListDTO.getSettlementStatus())));
            shipBillFeeListDTO.setCarrierTypeName(shipBillFeeListDTO.getCarrierType() == 1 ? "承运商" : "司机");
            shipBillFeeListDTO.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(shipBillFeeListDTO.getSource())));

            if (shipBillFeeListDTO.getCarrierType().intValue() == 2) {
                shipBillFeeListDTO.setCarrierName(shipBillFeeListDTO.getDriverName());
                shipBillFeeListDTO.setCarrierId(shipBillFeeListDTO.getDriverId());
                shipBillFeeListDTO.setCarrierCode(shipBillFeeListDTO.getDriverCode());
            }
        }
        return PageUtils.getPage(feeList);
    }

    @Override
    public void settlementSave(SettlementOrderVO vo) {
        if (ObjectUtil.isEmpty(vo.getIds()) || vo.getIds().size() < 1) {
            throw new PluginException("费用盘点不能为空");
        }

        UserEntity user = PlgFxUsrUtils.getUserEntity();
        // 1.判断结算名称是否存在
        Criteria criteria = Criteria.forClass(BmsShipbillSettlementModel.class);
        Restriction r1 = Restrictions.eq("settlementName", vo.getSettlementName());
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        List<BmsShipbillSettlementModel> models = settlementMapper.findByCriteria(criteria);
        if (ObjectUtil.isNotEmpty(models)) {
            throw new PluginException("结算名称已经存在，请不要重复添加");
        }
        // 多个费用结算时，判断结算部门，公司，承运商必须相同
        if (ObjectUtil.isNotEmpty(vo.getIds()) && vo.getIds().size() < 1) {
            throw new PluginException("请选择费用单");
        }
        List<Long> ids = vo.getIds();
        List<ShipBillFeeListDTO> detailModels = shipBillHeadMapper.findFeeListForSett(ids);

        Map<String, List<ShipBillFeeListDTO>> departmentMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getSettlementDepartment));
        if (departmentMap.size() > 1) {
            throw new PluginException("只有相同部门才能一起结算");
        }
        Map<String, List<ShipBillFeeListDTO>> companyMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getSettlementCompany));
        if (companyMap.size() > 1) {
            throw new PluginException("只有相同公司才能一起结算");
        }
        Map<Integer, List<ShipBillFeeListDTO>> carrierTypeMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getCarrierType));
        if (carrierTypeMap.size() > 1) {
            throw new PluginException("只有相同承运商类型才能一起结算");
        }
        if (detailModels.get(0).getCarrierType().intValue() == 2) {
            // 司机
           /*
            Map<String, List<ShipBillFeeListDTO>> driverMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getDriverName));
            if (driverMap.size() > 1 ) {
                throw new PluginException("只有相同司机才能一起结算");
            }
            Map<String, List<ShipBillFeeListDTO>> vehicleTypeMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getVehicleTypeName));
            if (vehicleTypeMap.size() > 1 ) {
                throw new PluginException("只有相同车型才能一起结算");
            }*/
            Map<String, List<ShipBillFeeListDTO>> affiliationMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getAffiliationName));
            if (affiliationMap.size() > 1) {
                throw new PluginException("只有相同隶属机构才能一起结算");
            }
        } else {
            // 承运商
            Map<String, List<ShipBillFeeListDTO>> carrierMap = detailModels.stream().collect(Collectors.groupingBy(ShipBillFeeListDTO::getCarrierCode));
            if (carrierMap.size() > 1) {
                throw new PluginException("只有相同承运商才能一起结算");
            }
        }
        RestMessage<String> settlementNo = maindataTmsResource.getCodeNumberByCode(BmsConstant.BMS_SHIP_BILL_SETTLEMENT_ID, "L");
        if (!settlementNo.isSuccess() || ObjectUtil.isEmpty(settlementNo)) {
            throw new PluginException("获取结算单号为空");
        }
        List<BmsShipbillSettlementDetailModel> detailModelList = Lists.newArrayList();
        for (ShipBillFeeListDTO detailModel : detailModels) {
            // 更新奋费用单状态为结算单生成
            BmsShipBillFeeDetailModel feeDetailModel = feeDetailMapper.findById(detailModel.getId(), BmsShipBillFeeDetailModel.class);
            if (ObjectUtil.isEmpty(feeDetailModel)) {
                throw new PluginException("查询费用单信息为空");
            }
            Integer expenseStatus = feeDetailModel.getExpenseStatus();
            if (expenseStatus == 5) {
                throw new PluginException(String.format("费用单[%s]已经生成结算单不能重复操作", feeDetailModel.getExpenseNo()));
            }
            BmsShipbillSettlementDetailModel settlementDetailModel = new BmsShipbillSettlementDetailModel();
            BeanUtils.copyProperties(detailModel, settlementDetailModel);
            settlementDetailModel.setId(null);
            settlementDetailModel.setExpenseStatus(detailModel.getExpenseStatus());
            settlementDetailModel.setExpenseType(detailModel.getExpenseType());
            settlementDetailModel.setSettlementDepartmentId(detailModel.getSettlementDepartmentId());
            settlementDetailModel.setSettlementDepartmentCode(detailModel.getSettlementDepartmentCode());
            settlementDetailModel.setSettlementDepartment(detailModel.getSettlementDepartment());
            settlementDetailModel.setSettlementCompanyId(detailModel.getCargoOwnerId());
            settlementDetailModel.setSettlementCompanyCode(detailModel.getCargoOwnerCode());
            settlementDetailModel.setSettlementCompany(detailModel.getCargoOwnerName());
            settlementDetailModel.setCreateperson(user.getNickname());
            settlementDetailModel.setCreatetime(DateUtil.date());
            settlementDetailModel.setEnterpriseId(user.getEnterpriseId());
            settlementDetailModel.setEnterpriseName(user.getEnterpriseName());
            settlementDetailModel.setSettlementNo(settlementNo.getData());
            settlementDetailModel.setUpdateperson(user.getNickname());
            settlementDetailModel.setUpdatetime(DateUtil.date());
            settlementDetailModel.setCheckStatus(detailModel.getCheckStatus());
            detailModelList.add(settlementDetailModel);


            feeDetailModel.setUpdateperson(user.getNickname());
            feeDetailModel.setUpdatetime(DateUtil.date());
            feeDetailModel.setCheckStatus(3);
            feeDetailMapper.update(feeDetailModel);
        }
        settlementDetailMapper.saveBatch(detailModelList);

        BmsShipbillSettlementModel bmsShipbillSettlementModel = new BmsShipbillSettlementModel();
        BeanUtils.copyProperties(vo, bmsShipbillSettlementModel);
        bmsShipbillSettlementModel.setCardEndDate(vo.getEndDate());
        bmsShipbillSettlementModel.setInvoiceEndDate(vo.getInvoiceEndDate());
        bmsShipbillSettlementModel.setSettlementDepartment(detailModelList.get(0).getSettlementDepartment());
        bmsShipbillSettlementModel.setSettlementDepartmentCode(detailModelList.get(0).getSettlementDepartmentCode());
        bmsShipbillSettlementModel.setSettlementDepartmentId(detailModelList.get(0).getSettlementDepartmentId());
        bmsShipbillSettlementModel.setSettlementNo(settlementNo.getData());
        bmsShipbillSettlementModel.setCreateperson(user.getNickname());
        bmsShipbillSettlementModel.setCreatetime(DateUtil.date());
        bmsShipbillSettlementModel.setUpdateperson(user.getNickname());
        bmsShipbillSettlementModel.setUpdatetime(DateUtil.date());
        bmsShipbillSettlementModel.setEnterpriseId(user.getEnterpriseId());
        bmsShipbillSettlementModel.setEnterpriseName(user.getEnterpriseName());
        bmsShipbillSettlementModel.setStatus(0);
        settlementMapper.save(bmsShipbillSettlementModel);

        BmsLogOperationModel logVO = new BmsLogOperationModel();
        logVO.setCreatetime(DateUtil.date());
        logVO.setCreateperson(user.getNickname());
        logVO.setEnterpriseId(user.getEnterpriseId());
        logVO.setEnterpriseName(user.getEnterpriseName());
        logVO.setOrderNo(settlementNo.getData());
        logVO.setLogMemo("结算单生成");
        logVO.setLogType(4);
        logOperationMapper.save(logVO);
    }

    @Override
    public ShipBillDTO detail(String shipbillNo) {
        if (ObjectUtil.isEmpty(shipbillNo)) {
            throw new PluginException("查询条件不能为空");
        }
        ShipBillDTO shipBillDTO = new ShipBillDTO();
        Criteria criteria = Criteria.forClass(BmsShipBillHeaderModel.class);
        Restriction r1 = Restrictions.eq("shipbillNo", shipbillNo);
        criteria.setRestriction(Restrictions.and(r1));
        List<BmsShipBillHeaderModel> headerModels = shipBillHeadMapper.findByCriteria(criteria);
        if (ObjectUtil.isEmpty(headerModels)) {
            throw new PluginException("获取运单信息为空");
        }
        BmsShipBillHeaderModel headerModel = headerModels.get(0);
        BeanUtils.copyProperties(headerModel, shipBillDTO);

        List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[]{
                BmsConstant.SHIPBILL_STATUS, // 运单状态
                BmsConstant.SHIPPER_TYPE, // 运输状态
                BmsConstant.ABNORMAL_STATUS, // 异常状态
                BmsConstant.ORDER_TYPE, // 订单类型
                BmsConstant.CONSIGNEE_TYPE, // 收货方类型
                BmsConstant.ORDER_BUSINESS_TYPE, // 订单业务类型
                BmsConstant.SOURCE, // 来源
                BmsConstant.SETTLEMENT_STATUS, // 核算状态
                BmsConstant.TEMPERATURE_REQUIREMENT// 温度要求
        });

        shipBillDTO.setOrderTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_TYPE, String.valueOf(headerModel.getOrderType())));
        shipBillDTO.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, BmsConstant.ORDER_BUSINESS_TYPE, String.valueOf(headerModel.getOrderBusinessType())));
        shipBillDTO.setTemperatureRequirementName(ConvertorUtil.getName(dicData, BmsConstant.TEMPERATURE_REQUIREMENT, String.valueOf(headerModel.getTemperatureRequirement())));
        shipBillDTO.setShipperTypeName(ConvertorUtil.getName(dicData, BmsConstant.SHIPPER_TYPE, String.valueOf(headerModel.getShipperType())));
        shipBillDTO.setConsigneeTypeName(ConvertorUtil.getName(dicData, BmsConstant.CONSIGNEE_TYPE, String.valueOf(headerModel.getConsigneeType())));
        shipBillDTO.setDeliveryMethodTypeName(headerModel.getDeliveryMethodType() == 1 ? "配送" : "自提");
        shipBillDTO.setTransportTypeName(headerModel.getTransportType() == 1 ? "整车" : "零担");
        shipBillDTO.setStatusName(ConvertorUtil.getName(dicData, BmsConstant.SHIPBILL_STATUS, String.valueOf(headerModel.getStatus())));
        shipBillDTO.setSourceName(ConvertorUtil.getName(dicData, BmsConstant.SOURCE, String.valueOf(headerModel.getSource())));
        shipBillDTO.setCarrierTypeName(headerModel.getCarrierType() == 1 ? "承运商" : "司机");

        Criteria dCriteria = Criteria.forClass(BmsShipBillDetailModel.class);
        Restriction r2 = Restrictions.eq("shipbillNo", shipbillNo);
        dCriteria.setRestriction(Restrictions.and(r2));
        List<BmsShipBillDetailModel> detailModels = shipBillDetailMapper.findByCriteria(dCriteria);

        List<ShipBillDetailDTO> list = Lists.newArrayList();
        for (BmsShipBillDetailModel detailModel : detailModels) {
            ShipBillDetailDTO dto = new ShipBillDetailDTO();
            BeanUtils.copyProperties(detailModel, dto);
            dto.setCargoThermosphereName(ConvertorUtil.getName(dicData, BmsConstant.TEMPERATURE_REQUIREMENT, String.valueOf(detailModel.getCargoThermosphere())));
            list.add(dto);
        }
        shipBillDTO.setList(list);
        return shipBillDTO;
    }
}