package pddapi

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi"
	"git.rosy.net.cn/baseapi/utils"
	"net/http"
	"sort"
	"strings"
	"time"
)

const (
	prodURL = "https://gw-api.pinduoduo.com/api/router"
	sigKey  = "sign"
)

type API struct {
	platformapi.APICookie

	appKey    string
	appSecret string
	client    *http.Client
	config    *platformapi.APIConfig
}

func New(appKey, appSecret string, config ...*platformapi.APIConfig) *API {
	curConfig := platformapi.DefAPIConfig
	if len(config) > 0 {
		curConfig = *config[0]
	}
	return &API{
		appKey:    appKey,
		appSecret: appSecret,
		client:    &http.Client{Timeout: curConfig.ClientTimeout},
		config:    &curConfig,
	}
}

func (a *API) signParam(params map[string]interface{}) (sig string) {
	var valueList []string
	for k, v := range params {
		if k != sigKey {
			if str := fmt.Sprint(v); str != "" {
				valueList = append(valueList, fmt.Sprintf("%s%s", k, str))
			}
		}
	}
	sort.Sort(sort.StringSlice(valueList))
	valueList = append(valueList, fmt.Sprintf("%s", a.appSecret))
	var valueList2 = make([]string, len(valueList)+1)
	at := copy(valueList2, valueList[:0])
	at += copy(valueList2[at:], []string{a.appSecret})
	copy(valueList2[at:], valueList[0:])
	sig = strings.Join(valueList2, "")
	binSig := md5.Sum([]byte(sig))
	sig = fmt.Sprintf("%X", binSig)
	return sig
}

func (a *API) AccessAPI(action string, isPost bool, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
	params := make(map[string]interface{})
	params["client_id"] = a.appKey
	params["type"] = action
	params["timestamp"] = time.Now().Unix()
	params = utils.MergeMaps(params, bizParams)
	signStr := a.signParam(params)
	params[sigKey] = signStr
	//fullURL := utils.GenerateGetURL(prodURL, action, nil)
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			var request *http.Request
			if !isPost {
				request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(prodURL, "", params), nil)
			} else {
				request, _ = http.NewRequest(http.MethodPost, prodURL, strings.NewReader(utils.Map2URLValues(params).Encode()))
			}
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if err == nil {
				if jsonResult1["error_response"] != nil {
					errLevel = platformapi.ErrLevelGeneralFail
					err = utils.NewErrorCode(jsonResult1["error_response"].(map[string]interface{})["sub_msg"].(string), utils.Int64ToStr(utils.MustInterface2Int64(jsonResult1["error_response"].(map[string]interface{})["sub_code"])))
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

func (a *API) AccessStorePage(fullURL string, bizParams map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
	if a.GetCookieCount() == 0 {
		return nil, fmt.Errorf("需要设置Store Cookie才能使用此方法")
	}
	data, _ := json.Marshal(bizParams)
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			var request *http.Request
			if isPost {
				request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(data)))
				request.Header.Set("Content-Type", "application/json;charset=utf-8")
			} else {
				request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(fullURL, "", bizParams), nil)
			}
			a.FillRequestCookies(request)
			return request
		},
		a.config,
		func(response *http.Response, bodyStr string, jsonResult1 map[string]interface{}) (errLevel string, err error) {
			if jsonResult1 == nil {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("mapData is nil")
			}
			if strings.Contains(bodyStr, "阿里妈妈") || strings.Contains(bodyStr, "联系客服") {
				return platformapi.ErrLevelRecoverableErr, fmt.Errorf("cookie可能过期了！")
			}
			if err == nil {
				if jsonResult1["error_response"] != nil {
					errLevel = platformapi.ErrLevelGeneralFail
					err = utils.NewErrorCode(jsonResult1["error_response"].(map[string]interface{})["zh_desc"].(string), jsonResult1["error_response"].(map[string]interface{})["code"].(string))
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}
