package com.xinelu.applet.service.logistics.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.xinelu.applet.service.logistics.LogisticsService;
import com.xinelu.applet.utils.LogisticsUtil;
import com.xinelu.applet.vo.logistics.DistinguishResultVO;
import com.xinelu.applet.vo.logistics.SearchMonitorResultVO;
import com.xinelu.common.config.LogisticsConfig;
import com.xinelu.common.core.domain.AjaxResult;
import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description 快递鸟物流查询接口业务层实现类
 * @Author 纪寒
 * @Date 2022-11-01 13:35:38
 * @Version 1.0
 */
@Slf4j
@Service
public class LogisticsServiceImpl implements LogisticsService {

    @Resource
    private LogisticsConfig logisticsConfig;
    @Resource
    private GoodsOrderMapper goodsOrderMapper;

    /**
     * 编码格式
     */
    private static final String CHARSET = "UTF-8";

    /**
     * 识别单号接口指令
     */
    private static final String DISTINGUISH_REQUEST_TYPE = "2002";

    /**
     * DataType=2，请求、返回数据类型均为JSON格式
     */
    private static final String DATA_TYPE = "2";

    /**
     * 即时查询接口指令
     */
    private static final String SEARCH_MONITOR_REQUEST_TYPE = "8001";

    /**
     * 顺丰快递编码
     */
    private static final String SF_SHIPPER_CODE_TYPE = "SF";

    /**
     * 根据快递快递单号查询物流信息
     *
     * @param orderNo   订单单号
     * @param expressNo 快递单号
     * @return 物流信息结果
     * @throws Exception 异常信息
     */
    @Override
    public AjaxResult queryLogisticsInfo(String orderNo, String expressNo) throws Exception {
        GoodsOrder goodsOrder = goodsOrderMapper.getGoodsOrderByOrderNo(orderNo);
        if (Objects.isNull(goodsOrder) || StringUtils.isBlank(goodsOrder.getPhone())) {
            return AjaxResult.error("当前订单信息不存在！");
        }
        if (StringUtils.isBlank(goodsOrder.getExpressNo())) {
            return AjaxResult.error("当前订单未发货，暂无订物流信息！");
        }
        //用户id、API KEY、正式地址等参数信息
        String eBusinessId = logisticsConfig.getEBusinessId();
        String apiKey = logisticsConfig.getApiKey();
        String expressBirdUrl = logisticsConfig.getExpressBirdUrl();
        Map<String, String> distinguishParam = buildDistinguishParam(expressNo, eBusinessId, apiKey);
        String distinguishResult = LogisticsUtil.sendPost(expressBirdUrl, distinguishParam);
        if (StringUtils.isBlank(distinguishResult)) {
            log.info("调用快递鸟识别单号返回结果为空，请求参数 ====> {}", distinguishParam.toString());
            return AjaxResult.error("当前订单暂无物流信息！");
        }
        DistinguishResultVO vo = JSONObject.parseObject(distinguishResult, DistinguishResultVO.class);
        if (Objects.isNull(vo) || BooleanUtils.isFalse(vo.getSuccess())) {
            log.info("调用快递鸟识别单号返回结果为空，请求参数 ====> {}", distinguishParam.toString());
            return AjaxResult.error("当前订单暂无物流信息！");
        }
        List<String> shipperCodeList = vo.getShippers().stream().filter(item -> StringUtils.isNotBlank(item.getShipperCode())).map(DistinguishResultVO.ShippersDTO::getShipperCode).distinct().collect(Collectors.toList());
        //循环查询快递信息
        SearchMonitorResultVO monitorResultVO = null;
        for (String shipperCode : shipperCodeList) {
            if (StringUtils.isBlank(shipperCode)) {
                continue;
            }
            //构建在途查询中即时查询接口参数信息
            Map<String, String> searchMonitorParam = buildSearchMonitorParam(expressNo, eBusinessId, apiKey, shipperCode, goodsOrder.getPhone());
            String searchMonitorResult = LogisticsUtil.sendPost(expressBirdUrl, searchMonitorParam);
            monitorResultVO = JSONObject.parseObject(searchMonitorResult, SearchMonitorResultVO.class);
            if (Objects.nonNull(monitorResultVO) && BooleanUtils.isTrue(monitorResultVO.getSuccess())) {
                List<SearchMonitorResultVO.TracesDTO> sortTraces = monitorResultVO.getTraces().stream()
                        .filter(item -> Objects.nonNull(item.getAcceptTime()))
                        .sorted(Comparator.comparing(SearchMonitorResultVO.TracesDTO::getAcceptTime).reversed()).collect(Collectors.toList());
                monitorResultVO.setTraces(sortTraces);
                monitorResultVO.setShipperName(vo.getShippers().stream().filter(item -> StringUtils.isNotBlank(item.getShipperName()))
                        .filter(item -> shipperCode.equals(item.getShipperCode())).map(DistinguishResultVO.ShippersDTO::getShipperName).findFirst().orElse(""));
                break;
            }
        }
        return AjaxResult.success(monitorResultVO);
    }

    /**
     * 构建识别单号参数信息
     *
     * @param expressNo   快递单号
     * @param eBusinessId 用户id
     * @param apiKey      API key
     * @return 参数信息
     * @throws Exception 异常信息
     */
    private Map<String, String> buildDistinguishParam(String expressNo, String eBusinessId,
                                                      String apiKey) throws Exception {
        String requestData = "{'LogisticCode': '" + expressNo + "'}";
        Map<String, String> params = new LinkedHashMap<>();
        params.put("RequestData", LogisticsUtil.urlEncoder(requestData, CHARSET));
        params.put("EBusinessID", eBusinessId);
        params.put("RequestType", DISTINGUISH_REQUEST_TYPE);
        String dataSign = LogisticsUtil.encrypt(requestData, apiKey, CHARSET);
        params.put("DataSign", LogisticsUtil.urlEncoder(dataSign, CHARSET));
        params.put("DataType", DATA_TYPE);
        return params;
    }

    /**
     * 构建即时查询物流单号信息
     *
     * @param expressNo   快递单号
     * @param eBusinessId 用户id
     * @param apiKey      API key
     * @param shipperCode 快递公司编码
     * @param phone       联系电话
     * @return 参数信息
     * @throws Exception 异常信息
     */
    private Map<String, String> buildSearchMonitorParam(String expressNo, String eBusinessId, String apiKey,
                                                        String shipperCode, String phone) throws Exception {
        Map<String, String> sysParamMap = new LinkedHashMap<>();
        sysParamMap.put("OrderCode", "");
        if (SF_SHIPPER_CODE_TYPE.equals(shipperCode)) {
            sysParamMap.put("CustomerName", phone.substring(7, 11));
        } else {
            sysParamMap.put("CustomerName", "");
        }
        sysParamMap.put("ShipperCode", shipperCode);
        sysParamMap.put("LogisticCode", expressNo);
        String requestData = JSON.toJSONString(sysParamMap);
        Map<String, String> params = new LinkedHashMap<>();
        params.put("RequestData", LogisticsUtil.urlEncoder(requestData, CHARSET));
        params.put("EBusinessID", eBusinessId);
        params.put("RequestType", SEARCH_MONITOR_REQUEST_TYPE);
        String dataSign = LogisticsUtil.encrypt(requestData, apiKey, CHARSET);
        params.put("DataSign", LogisticsUtil.urlEncoder(dataSign, CHARSET));
        params.put("DataType", DATA_TYPE);
        return params;
    }
}
