
package com.tmerclub.cloud.delivery.service.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.Header;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.tmerclub.cloud.api.delivery.vo.DeliveryInfoVO;
import com.tmerclub.cloud.api.delivery.vo.DeliveryItemInfoVO;
import com.tmerclub.cloud.api.platform.config.FeignShopConfig;
import com.tmerclub.cloud.common.bean.AliQuick;
import com.tmerclub.cloud.common.bean.Quick100;
import com.tmerclub.cloud.common.bean.QuickBird;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.util.PageUtil;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.util.Json;
import com.tmerclub.cloud.delivery.bo.DeliveryAliInfoBO;
import com.tmerclub.cloud.delivery.bo.DeliveryAliItemInfoBO;
import com.tmerclub.cloud.delivery.bo.DeliveryHundredInfoBO;
import com.tmerclub.cloud.delivery.bo.DeliveryHundredItemInfoBO;
import com.tmerclub.cloud.delivery.constant.DeliveryConstant;
import com.tmerclub.cloud.delivery.dto.DeliveryCompanyDTO;
import com.tmerclub.cloud.delivery.mapper.DeliveryCompanyMapper;
import com.tmerclub.cloud.delivery.model.DeliveryCompany;
import com.tmerclub.cloud.delivery.service.DeliveryCompanyService;
import com.tmerclub.cloud.delivery.vo.DeliveryCompanyVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.*;

/**
 * 物流公司
 *
 * @author tmerclub
 * @date 2020-12-07 15:10:00
 */
@Service
public class DeliveryCompanyServiceImpl implements DeliveryCompanyService {

    private static final Logger logger = LoggerFactory.getLogger(DeliveryCompanyServiceImpl.class);
    private static final int SUBLENGTH = 4;
    @Autowired
    private DeliveryCompanyMapper deliveryCompanyMapper;
    @Autowired
    private FeignShopConfig shopConfig;

    @Override
    public List<DeliveryCompanyVO> list() {
        return deliveryCompanyMapper.list();
    }

    @Override
    public DeliveryCompanyVO getByDeliveryCompanyId(Long deliveryCompanyId) {
        return deliveryCompanyMapper.getByDeliveryCompanyId(deliveryCompanyId);
    }

    @Override
    public void save(DeliveryCompany deliveryCompany) {
        checkDeliveryCompany(deliveryCompany);

        deliveryCompanyMapper.save(deliveryCompany);
    }

    private void checkDeliveryCompany(DeliveryCompany deliveryCompany) {
        if (deliveryCompanyMapper.countName(deliveryCompany.getName(), deliveryCompany.getDeliveryCompanyId()) > 0) {
            throw new LuckException("快递公司已存在");
        }
        if (StrUtil.isBlank(deliveryCompany.getAliNo()) && StrUtil.isBlank(deliveryCompany.getBirdNo()) && StrUtil.isBlank(deliveryCompany.getHundredNo())) {
            throw new LuckException("必须填写一个或多个物流公司编号");
        }
    }

    @Override
    public void update(DeliveryCompany deliveryCompany) {
        checkDeliveryCompany(deliveryCompany);
        deliveryCompanyMapper.update(deliveryCompany);
    }

    @Override
    public void deleteById(Long deliveryCompanyId) {
        deliveryCompanyMapper.deleteById(deliveryCompanyId);
    }

    @Override
    public PageVO<DeliveryCompanyVO> page(PageDTO pageDTO, DeliveryCompanyDTO deliveryCompanyDTO) {
        return PageUtil.doPage(pageDTO, () -> deliveryCompanyMapper.listBySearch(deliveryCompanyDTO));
    }

    @Override
    public DeliveryInfoVO query(DeliveryCompanyVO delivery, String expNo, String consigneeMobile) {
        try {
            if (Objects.nonNull(delivery)) {
                // 快递鸟查询
                QuickBird quickBird = shopConfig.getQuickBird();
                if (Objects.nonNull(quickBird) && BooleanUtil.isTrue(quickBird.getIsOpen())) {
                    return queryByQuickBird(delivery.getBirdNo(), expNo, quickBird, consigneeMobile);
                }
                // 快递100查询
                Quick100 quick100 = shopConfig.getQuick100();
                if (Objects.nonNull(quick100) && BooleanUtil.isTrue(quick100.getIsOpen())) {
                    return queryByQuick100(delivery.getHundredNo(), expNo, quick100, consigneeMobile);
                }
                // 阿里快递查询
                AliQuick aliQuickConfig = shopConfig.getAliQuickConfig();
                if (Objects.nonNull(aliQuickConfig) && BooleanUtil.isTrue(aliQuickConfig.getIsOpen())) {
                    return queryByAliQuick(delivery.getAliNo(), expNo, aliQuickConfig, consigneeMobile);
                }
            }
        } catch (Exception e) {
            logger.error("物流查询出错，查询单号：{}，报错信息：{}", expNo, e);
            // 查询出错
            throw new LuckException("查询出错");
        }
        DeliveryInfoVO deliveryInfoVO = new DeliveryInfoVO();
        deliveryInfoVO.setDvyFlowId(expNo);
        deliveryInfoVO.setCompanyName(delivery.getName());
        deliveryInfoVO.setCompanyHomeUrl(delivery.getHomeUrl());
        return deliveryInfoVO;
    }

    @Override
    public List<DeliveryCompanyVO> listByIds(Set<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return new ArrayList<>(Constant.INITIAL_CAPACITY);
        }
        return deliveryCompanyMapper.listByIds(ids);
    }

    private DeliveryInfoVO queryByQuickBird(String birdNo, String expNo, QuickBird quickBird, String consigneeMobile) throws UnsupportedEncodingException {
        String requestData = "{" +
                "'OrderCode': ''," +
                "'ShipperCode': '" + birdNo + "'," +
                "'LogisticCode': '" + expNo + "'," +
                // 快递为顺丰时需要传寄件人/收件人手机号后四位，为其他快递时，可不填或保留字段，不可传值
                "'CustomerName': '" + (Objects.equals(birdNo, QuickBird.SF_CODE) ? getLastFourOfMobile(consigneeMobile) : "") + "'," +
                "}";
        Map<String, Object> params = new HashMap<>(16);
        params.put("RequestData", URLEncoder.encode(requestData, "UTF-8"));
        params.put("EBusinessID", quickBird.geteBusinessID());
        String dataSign = Base64.encode(new Digester(DigestAlgorithm.MD5).digestHex(requestData + quickBird.getAppKey()), "UTF-8");
        params.put("DataSign", URLEncoder.encode(dataSign, "UTF-8"));
        params.put("RequestType", "1002");
        params.put("DataType", "2");
        String repJson = HttpUtil.post(quickBird.getReqUrl(), params);
        return JSON.parseObject(repJson, DeliveryInfoVO.class);
    }


    /**
     * 通过快递100查询
     *
     * @param expCode  物流公司编码
     * @param expNo    物流单号
     * @param quick100 配置信息
     * @return
     */
    private DeliveryInfoVO queryByQuick100(String expCode, String expNo, Quick100 quick100, String consigneeMobile) {
        Map<String, Object> paramMap = new HashMap<>(16);
        paramMap.put("com", expCode);
        paramMap.put("num", expNo);
        if (Objects.equals(expCode, Quick100.SF_CODE) || Objects.equals(expCode, Quick100.FENGWANG_CODE)) {
            // 快递100中顺丰速运和丰网速运必填收/寄件人手机号码，其他快递公司选填
            paramMap.put("phone", consigneeMobile);
        }
        paramMap.put("order", "desc");
        String param = JSON.toJSONString(paramMap);
        String sign = new Digester(DigestAlgorithm.MD5).digestHex(param + quick100.getKey() + quick100.getCustomer(), "UTF-8").toUpperCase(Locale.ROOT);
        Map<String, Object> params = new HashMap<>(16);
        params.put("param", param);
        params.put("sign", sign);
        params.put("customer", quick100.getCustomer());
        String repJson = HttpUtil.post(quick100.getReqUrl(), params);
        DeliveryHundredInfoBO hundredInfoBO = Json.parseObject(repJson, DeliveryHundredInfoBO.class);
        DeliveryInfoVO deliveryInfoVO = new DeliveryInfoVO();
        if (Objects.isNull(hundredInfoBO)
                || CollectionUtil.isEmpty(hundredInfoBO.getData())) {
            deliveryInfoVO.setTraces(new ArrayList<>(0));
            return deliveryInfoVO;
        }
        deliveryInfoVO.setState(hundredInfoBO.getState());
        List<DeliveryItemInfoVO> deliveryAliInfoList = new ArrayList<>(Constant.INITIAL_CAPACITY);
        for (DeliveryHundredItemInfoBO itemInfo : hundredInfoBO.getData()) {
            DeliveryItemInfoVO deliveryItemInfoVO = new DeliveryItemInfoVO();
            deliveryItemInfoVO.setAcceptStation(itemInfo.getContext());
            deliveryItemInfoVO.setAcceptTime(itemInfo.getFtime());
            deliveryAliInfoList.add(deliveryItemInfoVO);
        }
        deliveryInfoVO.setTraces(deliveryAliInfoList);
        return deliveryInfoVO;
    }

    /**
     * 通过阿里快递查询,返回当前包裹的快递信息
     *
     * @param expCode        物流公司编码
     * @param expNo          物流单号
     * @param aliQuickConfig 配置信息
     * @return 当前包裹的快递信息
     */
    private DeliveryInfoVO queryByAliQuick(String expCode, String expNo, AliQuick aliQuickConfig, String consigneeMobile) {
        Map<String, Object> params = new HashMap<>(16);
        if (Objects.equals(expCode, AliQuick.SF_CODE) && StrUtil.isNotBlank(consigneeMobile)) {
            // 使用阿里快递查询时，如果是顺丰单号，需要在单号后面拼接收件人手机号后四位
            expNo = expNo + ":" + getLastFourOfMobile(consigneeMobile);
        }
        params.put("type", expCode);
        params.put("no", expNo);
        params.put("Authorization", DeliveryConstant.CODE_HEADER + aliQuickConfig.getAliCode());
        //头信息，多个头信息多次调用此方法即可
        String repJson = HttpRequest.get(aliQuickConfig.getReqUrl())
                .header(Header.AUTHORIZATION, DeliveryConstant.CODE_HEADER + aliQuickConfig.getAliCode())
                .form(params)
                .execute().body();
        try {
            String data = JSONObject.parseObject(repJson).getString("result");
            DeliveryAliInfoBO deliveryAliInfoBO = Json.parseObject(data, DeliveryAliInfoBO.class);
            DeliveryInfoVO deliveryInfoVO = new DeliveryInfoVO();
            deliveryInfoVO.setCompanyName(deliveryAliInfoBO.getExpName());
            deliveryInfoVO.setCompanyHomeUrl(deliveryAliInfoBO.getExpSite());
            deliveryInfoVO.setDvyFlowId(deliveryAliInfoBO.getNumber());
            deliveryInfoVO.setState(deliveryAliInfoBO.getDeliverystatus());
            if (CollectionUtil.isEmpty(deliveryAliInfoBO.getList())) {
                deliveryInfoVO.setTraces(new ArrayList<>(0));
                return deliveryInfoVO;
            }
            List<DeliveryItemInfoVO> deliveryAliInfoList = new ArrayList<>(Constant.INITIAL_CAPACITY);
            for (DeliveryAliItemInfoBO itemInfo : deliveryAliInfoBO.getList()) {
                DeliveryItemInfoVO deliveryItemInfoVO = new DeliveryItemInfoVO();
                deliveryItemInfoVO.setAcceptStation(itemInfo.getStatus());
                deliveryItemInfoVO.setAcceptTime(itemInfo.getTime());
                deliveryAliInfoList.add(deliveryItemInfoVO);
            }
            deliveryInfoVO.setTraces(deliveryAliInfoList);
            return deliveryInfoVO;
        } catch (Exception e) {
            logger.warn("阿里物流查询错误{}", e.getMessage());
            return null;
        }

    }

    private String getLastFourOfMobile(String mobile) {
        // 获取手机号后四位
        if (Objects.isNull(mobile) || mobile.length() < SUBLENGTH) {
            return "";
        }
        return mobile.substring(mobile.length() - SUBLENGTH);
    }

}
