package pass

import (
	"PPOSUtils/utils"
	"PPOSUtils/vendorSDK/req"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"time"
)

//NewPassClient ...
func NewPassClient(appId, apiKey, apiDomain string) *PassClient {
	return &PassClient{
		appId:     appId,
		apiKey:    apiKey,
		apiDomain: apiDomain,
	}
}

//ClientProxy ...
type ClientProxy interface {
	Proxy(url string, param ClientParam, method string, v ...interface{}) (http.Header, []byte, error)
}

//ClientParam ...
type ClientParam interface {
	// 返回参数列表
	Params() (url.Values, error)
}

//PassClient ...
type PassClient struct {
	appId               string
	apiKey              string
	apiDomain           string
	timeOut             int
	responseCode        int64
	requestAddress      string
	paramsMiddleHander  func(url string, value url.Values) (url.Values, error)
	headerMiddleHandler utils.JaegerClientHeaderHandler
}

//在这里添加耗时比较长的SDK接口
func (that *PassClient) longTimeInterface() {
	_longTimeMp := utils.SliceString{
		//普通延迟路由
	}
	if _longTimeMp.In(that.requestAddress, _longTimeMp) {
		that.SetTimeOut(15)
	}
	that.longLongTimeInterface()
}
func (that *PassClient) longLongTimeInterface() {
	_longTimeMp := utils.SliceString{
		//长时间延迟路由
	}
	if _longTimeMp.In(that.requestAddress, _longTimeMp) {
		that.SetTimeOut(15 * 4)
	}
}

func (that *PassClient) SetTimeOut(second int) *PassClient {
	that.timeOut = second
	return that
}

func (that *PassClient) GetTimeOut() time.Duration {
	that.longTimeInterface()
	if that.timeOut == 0 {
		return time.Duration(5)
	}
	return time.Duration(that.timeOut)
}

func (that *PassClient) SetParamsMiddleHander(hander func(url string, value url.Values) (url.Values, error)) *PassClient {
	that.paramsMiddleHander = hander
	return that
}

func (that *PassClient) SetHeaderMiddleHandler(handler utils.JaegerClientHeaderHandler) *PassClient {
	that.headerMiddleHandler = handler
	return that
}

//_URLValues ...
func (that *PassClient) _getURLValues(url string, param ClientParam) (url.Values, error) {
	_params, _err := param.Params()
	if _err != nil {
		return nil, _err
	}
	if that.paramsMiddleHander != nil {
		_params, _err = that.paramsMiddleHander(url, _params)
	}
	return that._getSign(_params), nil
}

func (that *PassClient) _getSign(params url.Values) url.Values {
	params.Del("auth_sign")
	params.Set("app_id", that.appId)
	params.Set("nonce_str", that.getNonceStr())
	params.Set("auth_sign", utils.SignMD5(that.apiKey, params))
	return params
}

//获取错误码
func (that *PassClient) GetResponseCode() int64 {
	return that.responseCode
}

//处理响应
func (that *PassClient) GetData(url string, param ClientParam) (interface{}, error) {
	that.responseCode = 0
	that.requestAddress = url
	_resp, _err := that.Post(url, param)
	fmt.Print(_resp)
	if _err != nil {
		if strings.Contains(_err.Error(), "Timeout") {
			return nil, errors.New("系统繁忙，请稍后重试！")
		}
		return nil, _err
	}
	_result := map[string]interface{}{}
	if _err := _resp.ToJSON(&_result); _err != nil {
		return nil, _err
	}
	_slice := []string{
		"code",
		"message",
		"data",
	}
	for _, _v := range _slice {
		if _, _ok := _result[_v]; !_ok {
			return nil, errors.New("")
		}
	}
	that.responseCode = utils.ToInt64(_result["code"])
	if that.responseCode != 200 {
		return nil, errors.New(utils.ToString(_result["message"]))
	}
	return _result["data"], nil
}

//Proxy ...
func (that *PassClient) Proxy(urlPath string, param interface{}, method string, v ...interface{}) (http.Header, []byte, error) {
	_resp, _err := that._proxy(urlPath, param, strings.ToLower(method), v...)
	if _err != nil {
		return nil, nil, _err
	}
	_body, _err := _resp.ToBytes()
	_header := _resp.Response().Header
	return _header, _body, _err
}

func (that *PassClient) _proxy(urlPath string, param interface{}, method string, v ...interface{}) (*req.Resp, error) {
	that.requestAddress = urlPath
	switch _param := param.(type) {
	case ClientParam:
		_urlValues, _err := that._getURLValues(urlPath, _param)
		if _err != nil {
			return nil, _err
		}
		_sign := "Signature-ppos-pro/" + _urlValues.Get("auth_sign")
		_header := make(http.Header)
		_header.Add("Authorization", _sign)
		if that.headerMiddleHandler != nil {
			that.headerMiddleHandler(urlPath, _header)
		}
		_urlValues.Del("auth_sign")
		v = append(v, _urlValues, _header)
	case *req.BodyJson:
		_urlValues := utils.NewMP()
		_ = json.Unmarshal(_param.GetByte(), &_urlValues)
		fmt.Println("==========json sign befor:===========", _urlValues)
		_sign := "Signature-ppos-pro/" + utils.SignMD5(that.apiKey, _urlValues)
		_header := make(http.Header)
		_header.Add("Authorization", _sign)
		if that.headerMiddleHandler != nil {
			that.headerMiddleHandler(urlPath, _header)
		}
		v = append(v, _param, _header)
	}
	//
	req.SetTimeout(that.GetTimeOut() * time.Second)
	if method == "get" {
		return req.Get(that._buildAPI(urlPath), v...)
	}
	_rs, _err := req.Post(that._buildAPI(urlPath), v...)
	return _rs, _err
}

//Post ...
func (that *PassClient) Post(url string, param ClientParam, v ...interface{}) (*req.Resp, error) {
	_URLValues, _err := that._getURLValues(url, param)
	if _err != nil {
		return nil, _err
	}
	_sign := "Signature-ppos-pro/" + _URLValues.Get("auth_sign")
	_URLValues.Del("auth_sign")
	_header := make(http.Header)
	_header.Add("Authorization", _sign)
	if that.headerMiddleHandler != nil {
		that.headerMiddleHandler(url, _header)
	}
	v = append(v, _URLValues, _header)
	req.SetTimeout(that.GetTimeOut() * time.Second)
	return req.Post(that._buildAPI(url), v...)
}

func (that *PassClient) Get(url string, param ClientParam, v ...interface{}) (*req.Resp, error) {
	_URLValues, _err := that._getURLValues(url, param)
	if _err != nil {
		return nil, _err
	}
	url = that._buildAPI(url)
	fmt.Println(url, _URLValues)
	v = append(v, _URLValues)
	req.SetTimeout(that.GetTimeOut() * time.Second)
	return req.Get(url, v...)
}

//BuildAPI ...
func (that *PassClient) _buildAPI(paths ...string) string {
	var path = that.apiDomain
	for _, p := range paths {
		//
		p = strings.TrimSpace(p)
		if strings.HasPrefix(p, "http://") {
			return p
		}
		if strings.HasPrefix(p, "https://") {
			return p
		}
		//
		if len(p) > 0 {
			if strings.HasSuffix(path, "/") {
				path = path + p
			} else {
				if strings.HasPrefix(p, "/") {
					path = path + p
				} else {
					path = path + "/" + p
				}
			}
		}
	}
	return path
}

func (that *PassClient) getNonceStr() (nonceStr string) {
	chars := "abcdefghijklmnopqrstuvwxyz0123456789"
	for i := 0; i < 32; i++ {
		idx := rand.Intn(len(chars) - 1)
		nonceStr += chars[idx : idx+1]
	}
	return nonceStr
}

//发送json请求，参数data
func (that *PassClient) GetJsonData(url string, param ClientParam) (interface{}, error) {
	_data, _ := param.Params()
	//参数json序列化
	_jsonData := _data.Get("data")
	_http := http.Client{
		Timeout: 60 * time.Second, //60秒超时
	}
	//加入post请求参数
	request, err := http.NewRequest("POST", that._buildAPI(url), bytes.NewBuffer([]byte(_jsonData)))
	if err != nil {
		return nil, err
	}
	//增加header选项
	request.Header.Add("Content-Type", "application/json")
	//处理返回结果
	response, err := _http.Do(request)
	if err != nil {
		return nil, err
	}
	defer response.Body.Close()
	if http.StatusOK != response.StatusCode {
		return nil, err
	}
	//ReadAll
	_dataBody, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return nil, err
	}
	_result := utils.NewMP()
	_err := json.Unmarshal(_dataBody, &_result)
	if _err != nil {
		return nil, _err
	}
	_slice := []string{
		"code",
		"message",
		"data",
	}
	for _, _v := range _slice {
		if _, _ok := _result[_v]; !_ok {
			return nil, errors.New("")
		}
	}
	if utils.ToInt64(_result["code"]) != 200 {
		return nil, errors.New(utils.ToString(_result["message"]))
	}
	return _result["data"], nil
}
