package com.tzy.framework.express.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sf.csim.express.service.CallExpressServiceTools;
import com.sf.csim.express.service.EspServiceCode;
import com.tzy.common.config.ExpressConfig;
import com.tzy.common.constant.Constants;
import com.tzy.common.exception.ServiceException;
import com.tzy.common.utils.StringUtils;
import com.tzy.common.utils.http.HttpClientUtil;
import com.tzy.framework.express.dto.ExpressResult;
import com.tzy.framework.express.dto.Sf2TemplateDto;
import com.tzy.framework.express.dto.SfParamDto;
import com.tzy.framework.express.dto.SfTemplateDto;
import com.tzy.framework.express.service.ExpressSfService;
import com.tzy.framework.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;


/**
 * 顺丰物流
 */
@Slf4j
@Service
public class ExpressSfServiceImpl implements ExpressSfService {

    @Autowired
    private RedisUtils redisUtils;
    @Value("${express.sf.waybills_client_code:LSSFmyNTMl}")
    public String appkey ;
    @Value("${express.sf.waybills_check_word:QNBP4ya1bW9OYk6QVee8kQ1K0xWklOFm}")
    public String appSecret ;
    @Value("${express.sf.blx_authorization:Basic d2ViOmQ4YmZjMzQwMWE3NTg5ZTc4NGIwNmJkZmdhMmFkMWM0ZQ==}")
    public String authorization ;
    @Value("${express.sf.url:https://bspgw.sf-express.com/std/service}")
    public String sfUrl;
    @Value("${express.sf.box_url:https://sfapi-sbox.sf-express.com/std/service}")
    public String sfUrl_box;

    @Value("${express.sf.blx_username:13817769588}")
    private String username ;
    @Value("${express.sf.blx_pwd:CHaoDinRaoNeng568743}")
    private String pwd ;
    @Value("${express.sf.blx_public_key:MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtD3wUzP0KU4ZMInrLBqFhoUrspSGQMl27Y4z20ZJRiNezvYogtaKGynChl1GKQAZdq5SdNVwey0S6dHBfUMWmR5fpLyGbElPtbCRYBpTm4I+Wra++zD2rbdFA6K2BEBoxm0MYPqLGsQpvy57uePLUiPTMKQjKE6pQrm6r3pWkaOZx47a0LtGVGsxgnUG6y3LomdWF/dxEPjvVH/EaQ+9jEw1U6+qCVyh6qmkyrvECA3yNp++VkJa/QA/D9oZ6vGT3llPTxCWqj4SByqFabP5Dn9g1CAl4mcHFwFEsJwPsXBGA6cFj+xQ5xnXaP9Z+nMeLcgHMv+iCU77rY6ojnbzGwIDAQAB}")
    private String publicKeyStr ;

    /**
     * 获取token
     * @return
     */
    public JSONObject getToken(String type,String refreshToken){
        Map<Object, Object> sf_token = redisUtils.hmget(Constants.SF_TOKEN);
        if (null != sf_token && sf_token.get("access_token") != null && StringUtils.isNotEmpty(sf_token.get("access_token").toString())) {
            return (JSONObject) JSONObject.toJSON(sf_token);
        }

        log.debug("重新获取顺丰token");
        //type = "get_token";
        HttpClientUtil httpClientUtil = new HttpClientUtil(Constants.CONTENT_TYPE_FORM, authorization);
        Map<String,String> formData = new HashMap<>();
        if("refresh_token".equals(type)){//刷新token
            formData.put("grant_type", "refresh_token");
            formData.put("refresh_token",refreshToken);
        }else{
            formData.put("grant_type", "user_pwd");
            formData.put("username",username);
            formData.put("password",createPwd());
            formData.put("source","T01");
            formData.put("platform","200");
            formData.put("userType","2");
            formData.put("version","3");
            formData.put("app","2");
        }
        String ret = httpClientUtil.doPostFormV2(ExpressConfig.loginUrl, formData);
        if(StringUtils.isNotEmpty(ret)){
            JSONObject jsonObject = JSONObject.parseObject(ret);
            jsonObject.put("access_token",jsonObject.getString("token_type") + " " + jsonObject.getString("access_token"));
            redisUtils.hmset(Constants.SF_TOKEN,jsonObject,23*60*60);
            return jsonObject;
        }
        log.error("获取顺丰token失败,返回参数:{}",ret);
        throw new ServiceException("一键发货异常,请联系管理员");
    }



    /**
     * 下单
     * @param params
     * @return
     */
    public JSONObject downExpressOrder(List<SfParamDto> params){
        JSONObject token = getToken("", "");
        String access_token = "";
        if(null != token ){
            access_token = token.getString("access_token");
        }
        HttpClientUtil httpClientUtil = new HttpClientUtil(Constants.CONTENT_TYPE_JSON,access_token);
        JSONObject param = new JSONObject();
        param.put("expressOrderReqs",JSONArray.toJSON(params));
        log.info(" 请求token：》》》 {}",access_token);
        String ret = httpClientUtil.httpsPostRequest(ExpressConfig.downExpressOrderUrl, param);
        log.info(" 下单接口返回数据>>>{} ",ret);
        return JSONObject.parseObject(ret);
    }

    /**
     * 查询快递单
     * @return
     */
    public JSONObject queryOrderDownStatus(String orderId){
        JSONObject token = getToken("", "");
        String access_token = "";
        if(null != token ){
            access_token = token.getString("access_token");
        }
        HttpClientUtil httpClientUtil = new HttpClientUtil(Constants.CONTENT_TYPE_JSON,access_token);
        String ret = httpClientUtil.httpsGetRequest(ExpressConfig.queryOrderDownStatus + orderId);
        log.info(" 查询接口返回数据>>>{} ",ret);
        return JSONObject.parseObject(ret);
    }
    /**
     * 取消订单
     * @param orderId
     * @return
     */
    public JSONObject cancelOrder(String orderId,String sfCode){
        JSONObject token = getToken("", "");
        String access_token = "";
        if(null != token ){
            access_token = token.getString("access_token");
        }
        HttpClientUtil httpClientUtil = new HttpClientUtil(Constants.CONTENT_TYPE_JSON,access_token);
        String ret = httpClientUtil.httpsGetRequest(ExpressConfig.cancelOrder + orderId + (StringUtils.isNotEmpty(sfCode) ? "&waybill="+sfCode:""));
        log.info(" 取消接口返回数据>>>{} ",ret);
        return JSONObject.parseObject(ret);
    }


    /**
     * 获取密码
     * @return
     */
    private String createPwd(){
        try {
            JSONObject pwdJson = new JSONObject();
            pwdJson.put("p",pwd);
            pwdJson.put("t",System.currentTimeMillis());
            log.info(" 密码》》》{} ",pwdJson);
            byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyStr);
            PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] encodePasswordBytes = cipher.doFinal(pwdJson.toString().getBytes(StandardCharsets.UTF_8));
            return Base64.getEncoder().encodeToString(encodePasswordBytes);
        }catch (Exception e){
            log.error("生成顺丰登录密码错误：{}",e.getMessage());
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public ExpressResult getSfpdf( List<SfTemplateDto> sfTemplateDtos){
        try {
            //调用接口查询物流信息
            EspServiceCode testService = EspServiceCode.COM_RECE_CLOUD_PRINT_WAYBILLS;//打印面单
            CallExpressServiceTools client = CallExpressServiceTools.getInstance();
            Map<String, String> params = new HashMap<String, String>();
            String timeStamp = String.valueOf(System.currentTimeMillis());
            JSONObject jsonObject = new JSONObject();
            //150  180  210
            jsonObject.put("templateCode","fm_76130_standard_"+appkey);
            Object sfObj = JSONArray.toJSON(sfTemplateDtos);
            jsonObject.put("documents",sfObj);
            jsonObject.put("version","1.0");
            jsonObject.put("fileType","pdf");
            jsonObject.put("sync",true);
            String sendData = jsonObject.toString();
            params.put("partnerID", appkey);  // 顾客编码 ，对应丰桥上获取的clientCode
            params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
            params.put("serviceCode", testService.getCode());// 接口服务码
            params.put("timestamp", timeStamp);
            params.put("msgData", sendData);
            params.put("msgDigest", client.getMsgDigest(sendData, timeStamp, appSecret));
            String result = com.sf.csim.express.service.HttpClientUtil.post(sfUrl, params);
            log.info(" 同步获取面单返回结果：{} ",result);
            ExpressResult expressResult = new ExpressResult();
            if(StringUtils.isNotEmpty(result)&& result.startsWith("{") && result.endsWith("}") ){
                JSONObject retJson = JSONObject.parseObject(result);
                JSONObject apiResultData = retJson.getJSONObject("apiResultData");
                if(null != apiResultData && (Boolean) apiResultData.get("success")){
                    JSONObject resData = apiResultData.getJSONObject("obj");
                    if(null != resData ){
                        expressResult.put("files",JSONArray.parseArray(resData.getString("files")));
                        return expressResult;
                    }
                }else if(null != apiResultData){
                    return new ExpressResult().error(-1,"【"+apiResultData.getString("errorCode")+"】"+apiResultData.getString("errorMsg"));
                }else{
                    return new ExpressResult().error("未查到物流信息");
                }
            }
            return new ExpressResult().error("未查到物流信息");
        }catch (Exception e){
            e.printStackTrace();
        }
        return new ExpressResult()
                .error("未查到物流信息");
    }

    @Override
    public ExpressResult getSfpdf2(List<Sf2TemplateDto> sfTemplateDtos){
        try {
            //调用接口查询物流信息
            EspServiceCode testService = EspServiceCode.COM_RECE_CLOUD_PRINT_WAYBILLS;//打印面单
            CallExpressServiceTools client = CallExpressServiceTools.getInstance();
            Map<String, String> params = new HashMap<String, String>();
            String timeStamp = String.valueOf(System.currentTimeMillis());
            JSONObject jsonObject = new JSONObject();
            //150  180  210
            jsonObject.put("templateCode","fm_76130_standard_"+appkey);
            Object sfObj = JSONArray.toJSON(sfTemplateDtos);
            jsonObject.put("documents",sfObj);
            jsonObject.put("version","2.0");
            jsonObject.put("fileType","pdf");
            jsonObject.put("sync",true);
            String sendData = jsonObject.toString();
            params.put("partnerID", appkey);  // 顾客编码 ，对应丰桥上获取的clientCode
            params.put("requestID", UUID.randomUUID().toString().replace("-", ""));
            params.put("serviceCode", testService.getCode());// 接口服务码
            params.put("timestamp", timeStamp);
            params.put("msgData", sendData);
            params.put("msgDigest", client.getMsgDigest(sendData, timeStamp, appSecret));
            String result = com.sf.csim.express.service.HttpClientUtil.post(sfUrl, params);
            log.info(" 同步获取面单返回结果：{} ",result);
            ExpressResult expressResult = new ExpressResult();
            if(StringUtils.isNotEmpty(result)&& result.startsWith("{") && result.endsWith("}") ){
                JSONObject retJson = JSONObject.parseObject(result);
                JSONObject apiResultData = retJson.getJSONObject("apiResultData");
                if(null != apiResultData && (Boolean) apiResultData.get("success")){
                    JSONObject resData = apiResultData.getJSONObject("obj");
                    if(null != resData ){
                        expressResult.put("files",JSONArray.parseArray(resData.getString("files")));
                        return expressResult;
                    }
                }else if(null != apiResultData){
                    return new ExpressResult().error(-1,"【"+apiResultData.getString("errorCode")+"】"+apiResultData.getString("errorMsg"));
                }else{
                    return new ExpressResult().error("未查到物流信息");
                }
            }
            return new ExpressResult().error("未查到物流信息");
        }catch (Exception e){
            e.printStackTrace();
        }
        return new ExpressResult()
                .error("未查到物流信息");
    }


}
