package pposV2

import (
	"PPOSUtils/utils"
	"fmt"
	"math/rand"
	"net/http"

	"github.com/imroc/req"

	//"net/http"
	"errors"
	"net/url"
	"reflect"
	"strings"
)

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

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

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

//PPOSV2Client ...
type PPOSV2Client struct {
	appId     string
	apiKey    string
	apiDomain string
}

//_URLValues ...
func (that *PPOSV2Client) _getURLValues(param ClientParam) (value url.Values, err error) {
	p, _err := param.Params()
	if _err != nil {
		return nil, _err
	}
	fmt.Println("params", p)
	p.Set("app_id", that.appId)
	p.Set("nonce_str", that.getNonceStr())
	var sign = utils.SignMD5(that.apiKey, p)
	p.Set("sign", sign)
	return p, nil
}

func (that *PPOSV2Client) Get(url string, param ClientParam) (*req.Resp, error) {
	_URLValues, _err := that._getURLValues(param)
	if _err != nil {
		return nil, _err
	}
	_header := req.Header{
		"Accept":       "text/html,application/xhtml+xm…ml;q=0.9,image/webp,*/*;q=0.8",
		"Content-Type": "application/x-www-form-urlencoded",
	}
	url = that._buildAPI(url)
	fmt.Println(url, _URLValues)
	return req.Get(url, _URLValues, _header)
}

//Post ...
func (that *PPOSV2Client) Post(url string, param ClientParam) (interface{}, error) {
	_URLValues, _err := that._getURLValues(param)
	if _err != nil {
		return nil, _err
	}
	_header := req.Header{
		"Accept":       "application/json",
		"Content-Type": "application/x-www-form-urlencoded",
	}
	_resp, _err := req.Post(that._buildAPI(url), _URLValues, _header)
	fmt.Println(_resp)
	if _err != nil {
		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("")
		}
	}
	if utils.ToInt64(_result["code"]) != 200 {
		return nil, errors.New(utils.ToString(_result["message"]))
	}
	return _result["data"], nil
}

//Post ...
func (that *PPOSV2Client) PostV2(url string, param ClientParam, hasSign ...bool) (interface{}, error) {
	//
	_URLValues, _err := param.Params()
	if _err != nil {
		return nil, _err
	}
	//需要签名机制
	if len(hasSign) > 0 && hasSign[0] {
		_URLValues, _err = that._getURLValues(param)
		if _err != nil {
			return nil, _err
		}
	}
	//
	_header := req.Header{
		"Accept":       "application/json",
		"Content-Type": "application/x-www-form-urlencoded",
	}
	_resp, _err := req.Post(that._buildAPI(url), _URLValues, _header)
	fmt.Println(_resp)
	if _err != nil {
		return nil, _err
	}
	_result := map[string]interface{}{}
	if _err := _resp.ToJSON(&_result); _err != nil {
		return nil, _err
	}
	_slice := []string{
		"is_error",
	}
	for _, _v := range _slice {
		if _, _ok := _result[_v]; !_ok {
			return nil, errors.New("")
		}
	}
	_b, _ok := _result["is_error"].(bool)
	if !_ok {
		return nil, errors.New("response not 'is_error' params")
	}
	if _b == true {
		return nil, errors.New(utils.ToString(_result["error"]))
	}
	delete(_result, "is_error")
	//delete(_result, "error")
	return _result, nil
}

//BuildAPI ...
func (that *PPOSV2Client) _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 *PPOSV2Client) getNonceStr() (nonceStr string) {
	chars := "abcdefghijklmnopqrstuvwxyz0123456789"
	for i := 0; i < 32; i++ {
		idx := rand.Intn(len(chars) - 1)
		nonceStr += chars[idx : idx+1]
	}
	return nonceStr
}

//
func (that *PPOSV2Client) ParseResponeMp(mode interface{}, data interface{}, isMustValidate ...bool) error {
	_mp, _ok := data.(map[string]interface{})
	if !_ok {
		return errors.New("parse response error, data not map")
	}
	v := reflect.ValueOf(mode)
	if !v.IsNil() {
		t := reflect.TypeOf(mode)
		fieldNum := t.Elem().NumField()
		for i := 0; i < fieldNum; i++ {
			_type := t.Elem().Field(i).Type
			_k := t.Elem().Field(i).Tag.Get("json")
			if _k != "" {
				_v, _ok := _mp[_k]
				//非强制性验证字段属性
				if len(isMustValidate) > 0 && isMustValidate[0] == false && !_ok {
					continue
				}
				//强制验证字段必填
				if !_ok {
					return errors.New("response error:" + _k)
				}
				//字段所属类型
				switch _type.String() {
				case "int64":
					v.Elem().Field(i).SetInt(utils.ToInt64(_v))
				case "string":
					v.Elem().Field(i).SetString(utils.ToString(_v, true))
				case "bool":
					if _bool, _ok := _v.(bool); _ok {
						v.Elem().Field(i).SetBool(_bool)
					} else {
						v.Elem().Field(i).SetBool(false)
					}
				}
			}
		}
	}
	return nil
}
