package skdYujing

import (
	"PPOSUtils/utils"
	"encoding/json"
	"errors"
	"fmt"
	"math/rand"
	"net/http"
	"net/url"
	"reflect"
	"strings"
)

//SearchFull 搜索

func NewYuJingClient(apiDomain ...string) *YuJingClient {
	_yuJing := &YuJingClient{
		apiDomain: "http://api.ppdev.fun:8180", //预警系统的ip地址
	}
	if len(apiDomain) > 0 && apiDomain[0] != "" {
		_yuJing.apiDomain = apiDomain[0]
	}
	return _yuJing
}

type YuJingClient struct {
	appId     string
	apiKey    string
	apiDomain string
	//
	callbackMethod func(r *http.Request) (*http.Response, error)
}

func (that *YuJingClient) SetCallback(callbackMethod func(r *http.Request) (*http.Response, error)) *YuJingClient {
	//fmt.Println("===callbackMethod===", callbackMethod)
	that.callbackMethod = callbackMethod
	return that
}

//_URLValues ...
func (that *YuJingClient) _getURLValues(param ClientParam) (value url.Values, err error) {
	p, _err := param.Params()
	if _err != nil {
		return nil, _err
	}
	//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
}

//Post ...
func (that *YuJingClient) Post(url string, param ClientParam) (*http.Response, error) {
	//
	_URLValues, _err := that._getURLValues(param)
	if _err != nil {
		return nil, _err
	}
	_url := that._buildAPI(url)
	_request, _err := http.NewRequest("POST", _url, nil)
	_request.Header.Add("Accept", "application/json")
	_request.Header.Add("PROXYURL", _url)
	_request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	_request.Form = _URLValues
	//
	return that.callbackMethod(_request)
}

//Get ...
func (that *YuJingClient) Get(url string, paramData ClientParam) (*http.Response, error) {
	//
	_URLValues, _err := that._getURLValues(paramData)
	if _err != nil {
		return nil, _err
	}
	_url := that._buildAPI(url)
	//
	_param := param{_URLValues}
	if !_param.Empty() {
		paramStr := _param.Encode()
		if strings.IndexByte(_url, '?') == -1 {
			_url = _url + "?" + paramStr
		} else {
			_url = _url + "&" + paramStr
		}
	}
	//
	_request, _err := http.NewRequest("GET", _url, nil)
	if _err != nil {
		fmt.Println("YuJingClient.Get() err:", _err.Error())
		return nil, _err
	}
	_request.Header.Add("Accept", "application/json")
	_request.Header.Add("PROXYURL", _url)
	_request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
	//
	return that.callbackMethod(_request)
}

//BuildAPI ...
func (that *YuJingClient) _buildAPI(paths ...string) string {
	var path = that.apiDomain
	for _, p := range paths {
		p = strings.TrimSpace(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 *YuJingClient) 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 *YuJingClient) ParseList(data interface{}) (*struct {
	Count int
	Page  int
	Size  int
	List  interface{}
}, error) {
	_json, _err := json.Marshal(data)
	if _err != nil {
		return nil, _err
	}
	_list := &struct {
		Count int
		Page  int
		Size  int
		List  interface{}
	}{}
	if _err := json.Unmarshal(_json, &_list); _err != nil {
		return nil, _err
	}
	return _list, nil
}

//
func (that *YuJingClient) 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
}

type param struct {
	url.Values
}

func (p *param) getValues() url.Values {
	if p.Values == nil {
		p.Values = make(url.Values)
	}
	return p.Values
}

func (p *param) Copy(pp param) {
	if pp.Values == nil {
		return
	}
	vs := p.getValues()
	for key, values := range pp.Values {
		for _, value := range values {
			vs.Add(key, value)
		}
	}
}
func (p *param) Adds(m map[string]interface{}) {
	if len(m) == 0 {
		return
	}
	vs := p.getValues()
	for k, v := range m {
		vs.Add(k, fmt.Sprint(v))
	}
}

func (p *param) Empty() bool {
	return p.Values == nil
}
