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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
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.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.RestrictionBuilder;
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.app.constant.BussinessConstant;
import com.prolog.rdc.tms.app.constant.DataDictionaryConstant;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsLoadingBillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillDetailMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillHeaderMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillNodeTrackingMapper;
import com.prolog.rdc.tms.app.dao.mapper.TmsShipbillPackageMapper;
import com.prolog.rdc.tms.app.model.dto.business.ReceiptAndDeliveryCountDTO;
import com.prolog.rdc.tms.app.model.dto.business.ReceiptAndDeliveryDTO;
import com.prolog.rdc.tms.app.model.dto.business.ReceiptAndDeliveryItemDetailDTO;
import com.prolog.rdc.tms.app.model.dto.business.ReceiptAndDeliveryNodeDTO;
import com.prolog.rdc.tms.app.model.dto.business.ReceiptAndDeliveryPackageDetailDTO;
import com.prolog.rdc.tms.app.model.entity.ShipbillNodeTracking;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsLoadingBillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillDetailModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillHeaderModel;
import com.prolog.rdc.tms.app.model.entity.TmsShipbillPackageModel;
import com.prolog.rdc.tms.app.model.vo.business.ReceiptAndDeliveryQueryVO;
import com.prolog.rdc.tms.app.proxy.MainDataProxy;
import com.prolog.rdc.tms.app.service.business.ReceiptAndDeliveryService;
import com.prolog.rdc.tms.app.util.ConvertorUtil;
import com.prolog.rdc.tms.model.entity.SysRefdatadModel;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * @author hongbo.pan
 * @date 2022/10/31
 */
@Service
public class ReceiptAndDeliveryServiceImpl implements ReceiptAndDeliveryService {

    @Autowired
    private TmsShipbillHeaderMapper tmsShipbillHeaderMapper;

    @Autowired
    private TmsShipbillDetailMapper tmsShipbillDetailMapper;

    @Autowired
    private TmsShipbillPackageMapper tmsShipbillPackageMapper;

    @Autowired
    private TmsLoadingBillHeaderMapper tmsLoadingBillHeaderMapper;

    @Autowired
    private TmsLoadingBillDetailMapper tmsLoadingBillDetailMapper;

    @Autowired
    private TmsShipbillNodeTrackingMapper tmsShipbillNodeTrackingMapper;

    @Autowired
    private MainDataProxy mainDataProxy;

    @Autowired
    private ConvertorUtil convertorUtil;

    /**
     * 查询方式
     */
    private static final String QUERY_TYPE_NULL = "QUERY_TYPE_NULL";
    private static final String QUERY_TYPE_SHIP_BILL = "QUERY_TYPE_SHIP_BILL";
    private static final String QUERY_TYPE_LOADING_BILL = "QUERY_TYPE_LOADING_BILL";
    private static final String QUERY_TYPE_ORDER = "QUERY_TYPE_ORDER";
    private static final String QUERY_TYPE_WMS_ORDER = "QUERY_TYPE_WMS_ORDER";
    private static final String QUERY_TYPE_ERROR = "QUERY_TYPE_ERROR";

    /**
     * 合计数量
     * @param vo
     * @return
     */
    @Override
    public ReceiptAndDeliveryCountDTO count(ReceiptAndDeliveryQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");
        Pair<String,List<String>> result = validBillCode(vo.getBillCode());
        ReceiptAndDeliveryCountDTO countDTO = new ReceiptAndDeliveryCountDTO();
        if (QUERY_TYPE_ERROR.equals(result.getKey())) {
            countDTO.setAllNum(0);
            countDTO.setWaitShipNum(0);
            countDTO.setShippingNum(0);
            countDTO.setDeliveredNum(0);
            countDTO.setFinishNum(0);
            return countDTO;
        } else {
            vo.setShipBillIdList(result.getValue());
        }
        vo = setDataPermission(vo);
        Integer allNum = tmsShipbillHeaderMapper.countShipBillForReceiptAndDelivery(vo);
        vo.setTransportStatusList(Lists.newArrayList(DataDictionaryConstant.TRANSPORT_STATUS_PENDING_SHIP));
        Integer waitShipNum = tmsShipbillHeaderMapper.countShipBillForReceiptAndDelivery(vo);
        vo.setTransportStatusList(Lists.newArrayList(DataDictionaryConstant.TRANSPORT_STATUS_SHIPPING));
        Integer shippingNum = tmsShipbillHeaderMapper.countShipBillForReceiptAndDelivery(vo);
        vo.setTransportStatusList(Lists.newArrayList());
        vo.setStatusList(Lists.newArrayList(DataDictionaryConstant.SHIPBILL_STATUS_HD_PIC, DataDictionaryConstant.SHIPBILL_STATUS_HD_ZB));
        Integer deliveredNum = tmsShipbillHeaderMapper.countShipBillForReceiptAndDelivery(vo);
        vo.setStatusList(Lists.newArrayList(DataDictionaryConstant.SHIPBILL_STATUS_END));
        Integer finishNum = tmsShipbillHeaderMapper.countShipBillForReceiptAndDelivery(vo);
        countDTO.setAllNum(allNum);
        countDTO.setWaitShipNum(waitShipNum);
        countDTO.setShippingNum(shippingNum);
        countDTO.setDeliveredNum(deliveredNum);
        countDTO.setFinishNum(finishNum);
        return countDTO;
    }

    /**
     * 收发货查询
     * @param vo
     * @return
     */
    @Override
    public Page<ReceiptAndDeliveryDTO> findByCondition(ReceiptAndDeliveryQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");
        Pair<String,List<String>> result = validBillCode(vo.getBillCode());
        if (QUERY_TYPE_ERROR.equals(result.getKey())) {
            throw new BizException("单号【"+vo.getBillCode()+"】不存在，请重新输入");
        } else {
            vo.setShipBillIdList(result.getValue());
        }
        if (!QUERY_TYPE_NULL.equals(result.getKey())) {
            ReceiptAndDeliveryQueryVO permissionVO = new ReceiptAndDeliveryQueryVO();
            permissionVO = setDataPermission(permissionVO);
            permissionVO.setShipBillIdList(vo.getShipBillIdList());
            List<ReceiptAndDeliveryDTO> permissionDTOList = tmsShipbillHeaderMapper.shipBillForReceiptAndDeliveryQuery(permissionVO);
            if (CollectionUtil.isEmpty(permissionDTOList)) {
                String desc = "运单";
                if (QUERY_TYPE_LOADING_BILL.equals(result.getKey())) {
                    desc = "派车单";
                } else if (QUERY_TYPE_ORDER.equals(result.getKey())) {
                    desc = "订单";
                } else if (QUERY_TYPE_WMS_ORDER.equals(result.getKey())) {
                    desc = "WMS单";
                }
                throw new BizException("您无权查看"+desc+"【"+vo.getBillCode()+"】！");
            }
        }
        vo = setDataPermission(vo);
        PageUtils.startPage(vo.getPageNum(), vo.getPageSize());
        List<ReceiptAndDeliveryDTO> receiptAndDeliveryDTOList = tmsShipbillHeaderMapper.shipBillForReceiptAndDeliveryQuery(vo);
        if (CollectionUtil.isNotEmpty(receiptAndDeliveryDTOList)) {
            List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[] {
                    DataDictionaryConstant.SHIPBILL_STATUS, // 运单状态
                    DataDictionaryConstant.TRANSPORT_STATUS, // 运输状态
                    DataDictionaryConstant.ABNORMAL_STATUS, // 异常状态
                    DataDictionaryConstant.SCAN_STATUS, // 扫描状态
                    DataDictionaryConstant.LINE_CARRIER_TYPE, // 承运方类型
                    DataDictionaryConstant.DELIVERY_METHOD_TYPE, // 配送方式
                    DataDictionaryConstant.TRANSPORT_TYPE, // 运输类型(运输模式)
                    DataDictionaryConstant.TEMPERATURE_REQUIREMENT, // 温度要求
                    DataDictionaryConstant.SHIPPER_TYPE, // 发货方类型
                    DataDictionaryConstant.CONSIGNEE_TYPE, // 收货方类型
                    DataDictionaryConstant.ORDER_TYPE, // 订单类型
                    DataDictionaryConstant.ORDER_BUSINESS_TYPE // 订单业务类型
            });
            receiptAndDeliveryDTOList.forEach(dto -> {
                dto.setLoadingBillId(dto.getLoadingBillNo());
                dto.setReceiptAndDeliveryPackageDetailDTOList(getPackageDetailDTO(dto.getShipbillId()));
                dto.setReceiptAndDeliveryItemDetailDTOList(getItemDetailDTO(dto.getShipbillId()));
                dto.setStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.SHIPBILL_STATUS, String.valueOf(dto.getStatus())));
                dto.setTransportStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TRANSPORT_STATUS, String.valueOf(dto.getTransportStatus())));
                dto.setAbnormalStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.ABNORMAL_STATUS, String.valueOf(dto.getAbnormalStatus())));
                dto.setScanStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.SCAN_STATUS, String.valueOf(dto.getScanStatus())));
                dto.setOrderTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.ORDER_TYPE, String.valueOf(dto.getOrderType())));
                dto.setOrderBusinessTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.ORDER_BUSINESS_TYPE, String.valueOf(dto.getOrderBusinessType())));
                dto.setDeliveryMethodTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.DELIVERY_METHOD_TYPE, String.valueOf(dto.getDeliveryMethodType())));
                dto.setTransportTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TRANSPORT_TYPE, String.valueOf(dto.getTransportType())));
                dto.setTemperatureRequirementName(ConvertorUtil.getName(dicData, DataDictionaryConstant.TEMPERATURE_REQUIREMENT, String.valueOf(dto.getTemperatureRequirement())));
                dto.setShipperTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.SHIPPER_TYPE, String.valueOf(dto.getShipperType())));
                dto.setConsigneeTypeName(ConvertorUtil.getName(dicData, DataDictionaryConstant.CONSIGNEE_TYPE, String.valueOf(dto.getConsigneeType())));
                if (!DataDictionaryConstant.SHIPPER_TYPE_CK.equals(dto.getShipperType())) {
                    dto.setShipperName(dto.getShipperUnitName() + DataDictionaryConstant.Line_SYMBOL + dto.getShipperName());
                }
                if (!DataDictionaryConstant.CONSIGNEE_TYPE_CK.equals(dto.getConsigneeType())) {
                    dto.setConsigneeName(dto.getConsigneeUnitName() + DataDictionaryConstant.Line_SYMBOL + dto.getConsigneeName());
                }
            });
        }
        return PageUtils.getPage(receiptAndDeliveryDTOList);
    }

    @Override
    public List<ReceiptAndDeliveryNodeDTO> findNodeByShipBillId(String shipBillId) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        ToolKits.isParamNull(user, "当前人员没有操作权限");
        Criteria criteria = Criteria.forClass(ShipbillNodeTracking.class);
        Restriction r1 = Restrictions.eq("shipbillId", shipBillId);
        Restriction r2 = Restrictions.eq("enterpriseId", user.getEnterpriseId());
        criteria.setRestriction(Restrictions.and(r1, r2));
        criteria.setOrder(Order.newInstance().asc(new String[] { "updatetime" }));
        List<ShipbillNodeTracking> list = tmsShipbillNodeTrackingMapper.findByCriteria(criteria);
        List<ReceiptAndDeliveryNodeDTO> result = Lists.newArrayList();
        if (CollectionUtil.isNotEmpty(list)) {
            List<SysRefdatadModel> dicData = convertorUtil.getDictionary(new String[] {
                    DataDictionaryConstant.SHIPBILL_STATUS // 运单状态
            });
            result = list.stream().map(tracking -> {
                ReceiptAndDeliveryNodeDTO dto = new ReceiptAndDeliveryNodeDTO();
                BeanUtils.copyProperties(tracking, dto);
                dto.setStatusName(ConvertorUtil.getName(dicData, DataDictionaryConstant.SHIPBILL_STATUS, String.valueOf(dto.getStatus())));
                return dto;
            }).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 设置数据权限
     * @param vo
     * @return
     */
    private ReceiptAndDeliveryQueryVO setDataPermission(ReceiptAndDeliveryQueryVO vo) {
        UserEntity user = PlgFxUsrUtils.getUserEntity();
        vo.setEnterpriseId(user.getEnterpriseId());
        vo.setUserType(user.getUserType());
        // 承运商
        if (BussinessConstant.USER_TYPE_CYS.equals(user.getUserType())){
            vo.setCarrierId(Long.valueOf(user.getLoginUserCompanyInfo().getId()));
            vo.setCarrierStatusList(Lists.newArrayList(DataDictionaryConstant.CARRIER_SHIPBILL_STATUS_DISPATCHED_CHECK));
        } else {
            vo.setDeptList(user.getDepts());
            // 部门权限
            if (BussinessConstant.USER_DEPARTMENT_AUTH_Y.equals(user.getOwnedAllDataAuthFlag())) {
                vo.setIsDept("YES");
            } else {
                vo.setIsDept("NO");
                // 货主
                vo.setConsignorList(user.getConsignors());
                // 客户
                vo.setCustomerList(user.getCustomers());
                // 供应商
                vo.setSupplierList(user.getSuppliers());
                // 仓库
                vo.setWarehouseList(user.getWarehouses());
                List<Long> consigneeUnitIdList = Lists.newArrayList();
                if (CollectionUtil.isNotEmpty(vo.getCustomerList())) {
                    consigneeUnitIdList.addAll(vo.getCustomerList());
                }
                if (CollectionUtil.isNotEmpty(vo.getSupplierList())) {
                    consigneeUnitIdList.addAll(vo.getSupplierList());
                }
                if (CollectionUtil.isNotEmpty(vo.getWarehouseList())) {
                    consigneeUnitIdList.addAll(vo.getWarehouseList());
                }
                vo.setConsigneeUnitIdList(consigneeUnitIdList.stream().filter(ObjectUtil::isNotNull).distinct().collect(Collectors.toList()));
            }
        }
        return vo;
    }

    /**
     * 获取包裹明细
     * @param shipBillId
     * @return
     */
    private List<ReceiptAndDeliveryPackageDetailDTO> getPackageDetailDTO(String shipBillId) {
        List<ReceiptAndDeliveryPackageDetailDTO> result = Lists.newArrayList();
        Criteria ctr = Criteria.forClass(TmsShipbillPackageModel.class);
        Restriction rt1 = new RestrictionBuilder()
                .eq("shipbillId",shipBillId)
                .build();
        ctr.setRestriction(rt1);
        List<TmsShipbillPackageModel> packageList = tmsShipbillPackageMapper.findByCriteria(ctr);
        if (CollectionUtil.isNotEmpty(packageList)) {
            result = packageList.stream().map(packageModel -> {
                ReceiptAndDeliveryPackageDetailDTO packageDetailDTO = new ReceiptAndDeliveryPackageDetailDTO();
                BeanUtils.copyProperties(packageModel, packageDetailDTO);
                return packageDetailDTO;
            }).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 获取商品明细
     * @param shipBillId
     * @return
     */
    private List<ReceiptAndDeliveryItemDetailDTO> getItemDetailDTO(String shipBillId) {
        List<ReceiptAndDeliveryItemDetailDTO> result = Lists.newArrayList();
        Criteria ctr = Criteria.forClass(TmsShipbillDetailModel.class);
        Restriction rt1 = new RestrictionBuilder()
                .eq("shipbillId",shipBillId)
                .build();
        ctr.setRestriction(rt1);
        List<TmsShipbillDetailModel> detailModelList = tmsShipbillDetailMapper.findByCriteria(ctr);
        if (CollectionUtil.isNotEmpty(detailModelList)) {
            result = detailModelList.stream().map(detailModel -> {
                ReceiptAndDeliveryItemDetailDTO detailDTO = new ReceiptAndDeliveryItemDetailDTO();
                BeanUtils.copyProperties(detailModel, detailDTO);
                return detailDTO;
            }).collect(Collectors.toList());
        }
        return result;
    }

    /**
     * 校验输入单号
     * @param billCode
     * @return
     */
    private Pair<String,List<String>> validBillCode(String billCode) {
        if (StrUtil.isBlank(billCode)) {
            return new Pair<>(QUERY_TYPE_NULL, Lists.newArrayList());
        }
        String driverQrShowType = mainDataProxy.getSystemParamByCode(DataDictionaryConstant.DRIVER_QR_SHOW_TYPE);
        if (DataDictionaryConstant.DRIVER_QR_SHOW_TYPE_SHIP_BILL.equals(driverQrShowType)) {
            TmsShipbillHeaderModel tmsShipbillHeaderModel = tmsShipbillHeaderMapper.findById(billCode, TmsShipbillHeaderModel.class);
            //运单存在
            if (ObjectUtil.isNotNull(tmsShipbillHeaderModel)) {
                return new Pair<>(QUERY_TYPE_SHIP_BILL, Lists.newArrayList(billCode));
            }
        } else {
            TmsLoadingBillHeaderModel tmsLoadingBillHeaderModel = tmsLoadingBillHeaderMapper.findById(billCode, TmsLoadingBillHeaderModel.class);
            //派车单存在
            if (ObjectUtil.isNotNull(tmsLoadingBillHeaderModel)) {
                Criteria ctr = Criteria.forClass(TmsLoadingBillDetailModel.class);
                Restriction rt1 = new RestrictionBuilder()
                        .eq("loadingBillId",billCode)
                        .build();
                ctr.setRestriction(rt1);
                List<TmsLoadingBillDetailModel> list = tmsLoadingBillDetailMapper.findByCriteria(ctr);
                if (CollectionUtil.isNotEmpty(list)) {
                    return new Pair<>(QUERY_TYPE_LOADING_BILL, list.stream().map(TmsLoadingBillDetailModel::getShipbillId).distinct().collect(Collectors.toList()));
                }
            }
        }
        Criteria ctr = Criteria.forClass(TmsShipbillHeaderModel.class);
        Restriction rt1 = new RestrictionBuilder()
                .eq("orderNo",billCode)
                .build();
        ctr.setRestriction(rt1);
        List<TmsShipbillHeaderModel> orderList = tmsShipbillHeaderMapper.findByCriteria(ctr);
        if (CollectionUtil.isNotEmpty(orderList)) {
            return new Pair<>(QUERY_TYPE_ORDER, orderList.stream().map(TmsShipbillHeaderModel::getShipbillId).distinct().collect(Collectors.toList()));
        }
        rt1 = new RestrictionBuilder()
                .eq("wmsOrderNo",billCode)
                .build();
        ctr.setRestriction(rt1);
        List<TmsShipbillHeaderModel> wmsOrderList = tmsShipbillHeaderMapper.findByCriteria(ctr);
        if (CollectionUtil.isNotEmpty(wmsOrderList)) {
            return new Pair<>(QUERY_TYPE_WMS_ORDER, wmsOrderList.stream().map(TmsShipbillHeaderModel::getShipbillId).distinct().collect(Collectors.toList()));
        }
        return new Pair<>(QUERY_TYPE_ERROR, Lists.newArrayList());
    }
}
