package ejyapi

import (
	"crypto/md5"
	"encoding/json"
	"fmt"
	"net/http"
	"sort"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/platformapi"
	"git.rosy.net.cn/baseapi/utils"
)

const (
	sigKey  = "sign"
	TestUrl = "https://dev.ejiayou.com"
	Url     = "https://api.ejiayou.com"
)

type API struct {
	platformName string
	timeStamp    int64
	beforeKey    string
	afterKey     string
	client       *http.Client
	config       *platformapi.APIConfig
}

func (a *API) SetTimestamp(time int64) {
	a.timeStamp = time
}

func New(platformName string, beforeKey, afterKey string, config ...*platformapi.APIConfig) *API {
	curConfig := platformapi.DefAPIConfig
	if len(config) > 0 {
		curConfig = *config[0]
	}
	return &API{
		platformName: platformName,
		beforeKey:    beforeKey,
		afterKey:     afterKey,
		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("timestamp=%d", a.timeStamp))
	valueList = append(valueList, fmt.Sprintf("beforeKey=%s", a.beforeKey))
	valueList = append(valueList, fmt.Sprintf("afterKey=%s", a.afterKey))
	sig = strings.Join(valueList, "&")
	binSig := md5.Sum([]byte(sig))
	sig = fmt.Sprintf("%X", binSig)
	return sig
}

func (a *API) AccessAPI(action string, url string, bizParams map[string]interface{}, isPost bool) (retVal map[string]interface{}, err error) {
	data, _ := json.Marshal(bizParams)
	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(data)))
				request.Header.Set("Content-Type", "application/json")
			} else {
				request, _ = http.NewRequest(http.MethodGet, utils.GenerateGetURL(url, action, bizParams), nil)
			}
			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 GetStationListResult struct {
	StationType      int           `json:"stationType"`
	Latitude         string        `json:"latitude"`
	StationBannerPic string        `json:"stationBannerPic"`
	CityID           int           `json:"cityId"`
	ProvinceID       int           `json:"provinceId"`
	Adverts          []interface{} `json:"adverts"`
	CityName         string        `json:"cityName"`
	Phone            string        `json:"phone"`
	StationPic       string        `json:"stationPic"`
	District         string        `json:"district"`
	InvoiceType      int           `json:"invoiceType"`
	StationName      string        `json:"stationName"`
	Location         string        `json:"location"`
	ProvinceName     string        `json:"provinceName"`
	Prices           []struct {
		OilID         string   `json:"oilId"`
		StationPrice  string   `json:"stationPrice"`
		OilType       string   `json:"oilType"`
		DiscountPrice string   `json:"discountPrice"`
		CountryPrice  string   `json:"countryPrice"`
		OilgunCodes   []string `json:"oilgunCodes"`
		OilCode       string   `json:"oilCode"`
	} `json:"prices"`
	StarNum   string `json:"starNum"`
	StationID string `json:"stationId"`
	Longitude string `json:"longitude"`
}

//获取油站列表
func (a *API) GetStationList() (getStationListResult []*GetStationListResult, err error) {
	a.SetTimestamp(time.Now().Unix())
	params := make(map[string]interface{})
	// params["platformName"] = a.platformName
	sign := a.signParam(params)
	result, err := a.AccessAPI("oreo/ejiayou_open_api/stations/v2/"+a.platformName+"/"+sign+"/"+utils.Int64ToStr(a.timeStamp), Url, nil, false)
	if err == nil {
		utils.Map2StructByJson(result["data"], &getStationListResult, false)
	}
	return getStationListResult, err
}

type GetUserOrdersResult struct {
	ConsumeTimes string `json:"consumeTimes"`
	AllPaysum    string `json:"allPaysum"`
	SaveMoney    string `json:"saveMoney"`
	OrderList    []struct {
		Orderld         string `json:"orderld"`
		StationName     string `json:"stationName"`
		StationPic      string `json:"stationPic"`
		PayTime         string `json:"payTime"`
		Ordersum        string `json:"ordersum"`
		Reducesum       string `json:"reducesum"`
		Orderstate      int    `json:"orderstate"`
		HasstationPhone int    `json:"hasstationPhone"`
		StationPhone    string `json:"stationPhone"`
	} `json:"orderList"`
	OrderQuantity  int `json:"orderQuantity"`
	CurrentPageNum int `json:"currentPageNum"`
	AllPageNum     int `json:"allPageNum"`
	PersonalInfo   struct {
		JoinEjiayouDay string `json:"joinEjiayouDay"`
		Headurl        string `json:"headurl"`
		NickName       string `json:"nickName"`
		CenterPicURL   string `json:"centerPicUrl"`
		GlobalPicURL   string `json:"globalPicUrl"`
	} `json:"personalInfo"`
}

//获取用户个人订单
func (a *API) GetUserOrders(userPhone string, page int) (getUserOrdersResult *GetUserOrdersResult, err error) {
	a.SetTimestamp(time.Now().Unix())
	params := make(map[string]interface{})
	params["stationIds"] = ""
	params["page"] = page
	sign := a.signParam(params)
	result, err := a.AccessAPI("oreo/ejiayou_open_api/orders/histroy/"+userPhone+"/"+a.platformName+"/"+sign+"/"+utils.Int64ToStr(a.timeStamp), Url, params, true)
	if err == nil {
		utils.Map2StructByJson(result["data"], &getUserOrdersResult, false)
	}
	return getUserOrdersResult, err
}

type UserRefundResult struct {
	OrderID    string `json:"orderId"`
	Status     string `json:"status"`
	RefundTime string `json:"refundTime"`
	Msg        string `json:"msg"`
	UserPhone  string `json:"userPhone"`
}

//用户申请退款
func (a *API) UserRefund(orderId, userPhone, reason string) (userRefundResult *UserRefundResult, err error) {
	a.SetTimestamp(time.Now().Unix())
	params := make(map[string]interface{})
	params["reason"] = reason
	sign := a.signParam(params)
	result, err := a.AccessAPI("oreo/ejiayou_open_api/platform/refund/v1/"+a.platformName+"/"+userPhone+"/"+orderId+"/"+sign+"/"+utils.Int64ToStr(a.timeStamp), Url, params, false)
	if err == nil {
		utils.Map2StructByJson(result["data"], &userRefundResult, false)
	}
	return userRefundResult, err
}
