package com.liquidnet.common.third.zxlnft.biz;

import com.alibaba.fastjson.JSONObject;
import com.liquidnet.common.third.zxlnft.config.ZxlnftConfig;
import com.liquidnet.common.third.zxlnft.constant.ZxlErrorEnum;
import com.liquidnet.common.third.zxlnft.dto.wallet.*;
import com.liquidnet.common.third.zxlnft.exception.ZxlNftException;
import com.liquidnet.common.third.zxlnft.service.WalletSdkService;
import com.liquidnet.commons.lang.util.BeanUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.NameValuePair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import java.beans.IntrospectionException;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;

/**
 * @author AnJiabin <anjiabin@zhengzai.tv>
 * @version V1.0
 * @Description: TODO
 * @class: ZxlnftBiz
 * @Package com.liquidnet.common.third.zxlnft
 * @Copyright: LightNet @ Copyright (c) 2021
 * @date 2022/2/21 11:19
 */
@Slf4j
@Component
public class ZxlnftBiz {
    @Autowired
    private ZxlnftConfig zxlnftConfig;
    @Autowired
    private WalletSdkService walletSdkService;

    /**
     * 构造鉴权方案二
     * @param commonHeader
     */
    public void buildHeader(MultiValueMap<String, String> commonHeader){
        GenerateApiSignReq req = GenerateApiSignReq.getNew();
        req.setAppId("");
        req.setAppKey("");
        GenerateApiSignResp resp = walletSdkService.generateApiSign(req);

        commonHeader.clear();
        commonHeader.add("Signature", resp.getSignData().getSignature());
        commonHeader.add("Signature-Time", resp.getSignData().getSignatureTime());
        commonHeader.add("Nonce", resp.getSignData().getNonce());
        commonHeader.add("Content-Type", "application/json;charset=utf-8");

        log.debug("buildHeader ---> {}",JsonUtils.toJson(commonHeader));
    }

    /**
     * 构造鉴权方案一
     * @param commonHeader
     */
    public void buildPlatFormHeader(MultiValueMap<String, String> commonHeader){
        GenerateApiSignReq req = GenerateApiSignReq.getNew();
        req.setAppId(zxlnftConfig.getAppId());
        req.setAppKey(zxlnftConfig.getAppKey());
        GenerateApiSignResp resp = walletSdkService.generateApiSign(req);

        commonHeader.clear();
        commonHeader.add("App-Id", req.getAppId());
        commonHeader.add("Signature", resp.getSignData().getSignature());
        commonHeader.add("Signature-Time", resp.getSignData().getSignatureTime());
        commonHeader.add("Nonce", resp.getSignData().getNonce());
        commonHeader.add("Content-Type", "application/json;charset=utf-8");

        log.debug("buildPlatFormHeader ---> {}",JsonUtils.toJson(commonHeader));
    }

    public <T> T buildNftRespObj(String response,Class<T> tClass){
        T resp = null;
        try {
            /**
             * 构造返回结果
             */
            resp = this.buildNftRespObj(response,tClass,true);
//            log.info(tClass.getName()+"--->>> return result : {} ",resp.toString());
        } catch (ZxlNftException e){
            log.error("buildNftRespObj biz error response: {}", JsonUtils.toJson(response),e);
            throw new ZxlNftException(e.getCode(),e.getMsg());
        }catch (Exception e) {
            log.error("buildNftRespObj sys error response: {}", JsonUtils.toJson(response),e);
            throw new ZxlNftException(ZxlErrorEnum.SYSTEM_ERROR.getCode(),e.getMessage());
        }
        return resp;
    }

    public <T> T buildNftRespObj(String response,Class<T> tClass,boolean isJson){
        T resp = null;
        try {
            resp = tClass.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        JSONObject json = JSONObject.parseObject(response);
        if (json.containsKey("retCode") && json.containsKey("data") && json.getInteger("retCode").intValue() == 0) {
            if(isJson){
                JSONObject data = json.getJSONObject("data");
                resp = JsonUtils.fromJson(data.toJSONString(),tClass);
            }else{
                String rsData = json.getString("data");
                resp = (T)rsData;
            }

        }
        else {
            if (json.containsKey("retCode") && json.getInteger("retCode").intValue() != 0) {
                throw new ZxlNftException(String.valueOf(json.getInteger("retCode")), json.getString("retMsg"));
            }
//            throw new ZxlNftException(json.getString("retCode"), json.getString("retMsg"));
        }
        return resp;
    }

    /**
     * 接口内签名
     * @param key
     * @param data
     * @return
     */
    public String createSign(String key,String data){
        SignByPriKeyReq req = SignByPriKeyReq.getNew();
        req.setPriKey(key);
        req.setData(data);
        SignByPriKeyResp resp = walletSdkService.signByPriKey(req);
        return resp.getSignedData();
    }

    /**
     * 获取hash
     * @param data
     * @return
     */
    public String getHashString(String data){
        SM3HashEncodeResp sm3HashEncodeResp = null;
        try {
            SM3HashEncodeReq req = SM3HashEncodeReq.getNew();
            byte[] fileByteArray = this.getNftFileByteArray(data);
            req.setData(fileByteArray);
            sm3HashEncodeResp = walletSdkService.sM3HashEncode(req);
            return sm3HashEncodeResp.getDigest();
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.getMessage(),e);
        }
        return null;
    }

    /**
     * 构造GET请求url
     * @param requestUrl
     * @param tClass
     * @param <T>
     * @return
     */
    public <T> String buildGetRequestUrl(String requestUrl,Class<T> tClass,Object obj){
        //拼接请求url
        URI build = null;
//        String reqUrl = null;
//        try {
//            UriComponentsBuilder builder = UriComponentsBuilder
//                    .fromHttpUrl(requestUrl).queryParams(this.buildGetReqParams(obj));
//            reqUrl =  builder.build(true).toString();
//        }
//        catch (Exception e) {
//            e.printStackTrace();
//        }

        List<NameValuePair> params = BeanUtil.convertBeanToNameValuePairList(obj);
        requestUrl = requestUrl.concat("?");
        for(NameValuePair nameValuePair:params){
            try {
                requestUrl = requestUrl.concat("&"+nameValuePair.getName()+"="+ URLEncoder.encode(nameValuePair.getValue().toString(), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
//        try {
//            build = new URIBuilder(requestUrl).addParameters(params).build();
//        } catch (URISyntaxException e) {
//            e.printStackTrace();
//        }

//        if(build.toString().contains("%20")){
//            return build.toString().replaceAll("%20","+");
//        }
        return requestUrl;
    }

    public MultiValueMap<String, String> buildGetReqParams(Object obj){
        Map<String,Object> map = null;
        try {
            map = BeanUtil.convertBeanToMap(obj,false);
        } catch (IntrospectionException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        MultiValueMap<String, String>  params = new LinkedMultiValueMap();
        // Map集合循环遍历方式三 推荐，尤其是容量大时
        for (Map.Entry<String, Object> m : map.entrySet()) {
            params.add(m.getKey(),m.getValue().toString());
        }
        return params;

    }

    /**
     * 获取素材字节数组
     * @param url
     * @return
     */
    public byte[] getNftFileByteArray(String url) {
        try {
            HttpURLConnection httpUrl = (HttpURLConnection) new URL(url).openConnection();
            httpUrl.connect();
            InputStream ins = httpUrl.getInputStream();
            byte[] arr = new byte[1024];
            ByteArrayOutputStream out=new ByteArrayOutputStream();
            int len=0;
            while((len=ins.read(arr))!=-1){
                out.write(arr, 0, len);
            }
            out.close();
            return out.toByteArray();
        } catch (Exception e) {
            log.error("inputStreamToFileUrlError", e);
            return null;
        }
    }
}
