package fnpsapi

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

const (
	merchantID = "51658"

	URLv3 = "https://open-anubis.ele.me/anubis-webapi/v3/invoke"
)

type APIv3 struct {
	accessToken string
	appID       string
	appSecret   string

	locker sync.RWMutex
	client *http.Client
	config *platformapi.APIConfig
}

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

func (a *APIv3) SetTokenv3(token string) {
	a.locker.Lock()
	defer a.locker.Unlock()
	a.accessToken = token
}

func (a *APIv3) signParamv3(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))
	sig = strings.Join(valueList, "&")
	sig = a.appSecret + sig
	binSig := sha1.Sum([]byte(sig))
	sig = fmt.Sprintf("%x", binSig)
	return sig
}

func (a *APIv3) AccessAPIv3(action string, url string, bizParams map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
	params := make(map[string]interface{})
	params["timestamp"] = time.Now().UnixNano()
	params["app_id"] = a.appID
	params["merchant_id"] = merchantID
	params["version"] = "1.0"
	params["access_token"] = a.accessToken
	data, _ := json.Marshal(bizParams)
	params["business_data"] = string(data)
	signStr := a.signParamv3(params)
	params[sigKey] = signStr
	datas, _ := json.Marshal(params)
	fullURL := utils.GenerateGetURL(url, action, nil)
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			var request *http.Request
			if isPost {
				request, _ = http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(datas)))
			} else {
				request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(url, action, params), nil)
			}
			request.Header.Set("Content-Type", "application/json")
			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 utils.MustInterface2Int64(jsonResult1["code"]) != 200 {
					errLevel = platformapi.ErrLevelGeneralFail
					err = utils.NewErrorCode(jsonResult1["msg"].(string), utils.Int64ToStr(utils.MustInterface2Int64(jsonResult1["code"])))
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

type PreCreateOrderParam struct {
	PartnerOrderCode      string        `json:"partner_order_code"`
	OutShopCode           string        `json:"out_shop_code"`
	OrderType             int           `json:"order_type"`
	PositionSource        int           `json:"position_source"` // 3:高德地图
	ReceiverAddress       string        `json:"receiver_address"`
	ReceiverLongitude     float64       `json:"receiver_longitude"`
	ReceiverLatitude      float64       `json:"receiver_latitude"`
	GoodsTotalAmountCent  float64       `json:"goods_total_amount_cent"`
	GoodsActualAmountCent float64       `json:"goods_actual_amount_cent"`
	GoodsWeight           float64       `json:"goods_weight"`
	GoodsCount            float64       `json:"goods_count"`
	GoodsItemList         []*ItemsJSON2 `json:"goods_item_list"`
}

type ItemsJSON2 struct {
	ItemName             string  `json:"item_name"`
	ItemQuantity         int     `json:"item_quantity"`
	ItemAmountCent       float64 `json:"item_amount_cent"`
	ItemActualAmountCent float64 `json:"item_actual_amount_cent"`
}

func (a *APIv3) PreCreateOrder(preCreateOrderParam *PreCreateOrderParam) (queryOrderResult *QueryOrderResult, err error) {
	result, err := a.AccessAPIv3("preCreateOrder", URLv3, utils.Struct2FlatMap(preCreateOrderParam), true)
	if err == nil {
		utils.Map2StructByJson(result["data"], &queryOrderResult, false)
	}
	return queryOrderResult, err
}
