package com.hzs.third.express.service.impl;

import cn.hutool.http.HttpUtil;
import com.google.gson.*;
import com.hzs.common.core.constant.HttpStatus;
import com.hzs.common.core.domain.R;
import com.hzs.third.express.config.ExpressConfig;
import com.hzs.third.express.dto.ExpressDTO;
import com.hzs.third.express.dto.ExpressDetail;
import com.hzs.third.express.param.QueryTrackParam;
import com.hzs.third.express.service.IExpressService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 快递100
 */
@Service
@Slf4j
public class ExpressServiceImpl implements IExpressService {

    @Autowired
    private ExpressConfig expressConfig;

    @Override
    public R<ExpressDTO> expressTrackInfo(String trackingNumber, String mobile) {
        String customer = expressConfig.getCustomer();
        String key = expressConfig.getKey();
        String url = expressConfig.getUrl();

        QueryTrackParam queryTrackParam = new QueryTrackParam();
        queryTrackParam.setNum(trackingNumber);
        queryTrackParam.setPhone(mobile);
        String param = new Gson().toJson(queryTrackParam);

        Map<String, Object> params = new HashMap<>(3);
        params.put("param", param);
        params.put("customer", customer);
        params.put("sign", querySign(param, key, customer));
        String httpResult = HttpUtil.post(url, params);
        return this.parseResult(httpResult);
    }

    /**
     * 解析返回的结果集
     *
     * @param httpResult 结果集
     * @return ExpressDTO
     */
    private R<ExpressDTO> parseResult(String httpResult) {
        ExpressDTO expressDTO = new ExpressDTO();
        JsonObject resultJson = JsonParser.parseString(httpResult).getAsJsonObject();
        //三方接口正常返回
        if (resultJson.has("status")) {
            List<ExpressDetail> expressDetails = new ArrayList<>();
            String status = resultJson.get("status").getAsString();
            if (Integer.parseInt(status) == (HttpStatus.SUCCESS)) {
                Gson gson = new Gson();
                //物流状态
                String logisticsStatus = resultJson.get("state").getAsString();
                expressDTO.setLogisticsStatus(logisticsStatus);
                //解析物流信息
                JsonArray jsonArray = resultJson.getAsJsonArray("data");
                for (JsonElement jsonElement : jsonArray) {
                    JsonObject expressJson = jsonElement.getAsJsonObject();
                    ExpressDetail expressDetail = gson.fromJson(expressJson, ExpressDetail.class);
                    expressDetails.add(expressDetail);
                }
            }
            expressDTO.setExpressDetails(expressDetails);
            return R.ok(expressDTO);
        } else {
            String returnCode = resultJson.get("returnCode").getAsString();
            int code = Integer.parseInt(returnCode);
            String message = resultJson.get("message").getAsString();
            log.info("快递接口返回状态值: {},信息为: {}", returnCode, message);
            if (HttpStatus.BAD_REQUEST == code) {
                message = "找不到对应公司";
            } else if (HttpStatus.UNAUTHORIZED == code) {
                message = "不支持此快递公司";
            } else if (HttpStatus.ERROR == code) {
                message = "查询无结果，请隔段时间再查";
            } else {
                message = "调用接口异常";
            }
            return R.fail(message);
        }
    }

    /**
     * 快递100加密方式统一为MD5后转大写
     *
     * @param msg 加密内容
     * @return String
     */
    private String sign(String msg) {
        return DigestUtils.md5Hex(msg).toUpperCase();
    }

    /**
     * 查询加密
     *
     * @param param    请求参数
     * @param key      KEY
     * @param customer 受权码
     * @return String
     */
    private String querySign(String param, String key, String customer) {
        String sb = param +
                key +
                customer;
        return sign(sb);
    }
}
