package yinbaoapi

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"
	url           = "https://area27-win.pospal.cn:443/pospal-api2/openapi/v1"
	ImageUrl      = "http://pospalstoreimg.area27.pospal.cn"
	statusSuccess = "success"

	skuExistErrCode    = "5004"
	skuNotExistErrCode = "5001"
	AppIDErrCode       = "1034"
	AppKeyErrCode      = "1032"

	SkuStatusEnable   = 1
	SkuStatusDisabled = 0
	SkuStatusDeleted  = -1

	PageMaxID = "LAST_RESULT_MAX_ID"
)

type API struct {
	platformapi.APICookie

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

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

func (a *API) AccessAPI(action string, bizParams map[string]interface{}) (retVal map[string]interface{}, err error) {
	bizParams["appId"] = a.appID
	fullURL := utils.GenerateGetURL(url, action, nil)
	result, _ := json.MarshalIndent(bizParams, "", " ")
	err = platformapi.AccessPlatformAPIWithRetry(a.client,
		func() *http.Request {
			request, _ := http.NewRequest(http.MethodPost, fullURL, strings.NewReader(string(result)))
			result2 := a.appKey + string(result)
			binSig := md5.Sum([]byte(result2))
			request.Header.Set("User-Agent", "openApi")
			request.Header.Set("accept-encoding", "gzip,deflate")
			request.Header.Set("data-signature", fmt.Sprintf("%X", binSig))
			request.Header.Set("time-stamp", utils.Int64ToStr(time.Now().Unix()))
			request.Header.Set("Content-Type", "application/json; charset=utf-8")
			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["status"] != statusSuccess {
					errLevel = platformapi.ErrLevelGeneralFail
					errMsg := ""
					for _, v := range jsonResult1["messages"].([]interface{}) {
						errMsg += v.(string)
					}
					err = utils.NewErrorCode(errMsg, utils.Int64ToStr(utils.Interface2Int64WithDefault(jsonResult1["errorCode"], 0)))
				}
				retVal = jsonResult1
			}
			return errLevel, err
		})
	return retVal, err
}

type ProductInfo struct {
	CategoryUID        int64    `json:"categoryUid"`
	Name               string   `json:"name"`
	Barcode            string   `json:"barcode"`
	BuyPrice           *float64 `json:"buyPrice"`
	SellPrice          *float64 `json:"sellPrice"`
	Stock              *float64 `json:"stock"`
	Pinyin             string   `json:"pinyin"`
	Description        string   `json:"description"`
	IsCustomerDiscount *int     `json:"isCustomerDiscount"`
	SupplierUID        int      `json:"supplierUid"`
	Enable             *int     `json:"enable"`
	CustomerPrice      *float64 `json:"customerPrice"`
	Attribute1         string   `json:"attribute1"`
	Attribute2         string   `json:"attribute2"`
	Attribute3         string   `json:"attribute3"`
	Attribute4         string   `json:"attribute4"`
	UID                int64    `json:"uid"`
}

type ProductInfoParam struct {
	ProductInfo *ProductInfo
	AppID       string `json:"appId"`
}

type AddProductInfoResult struct {
	ID              int     `json:"id"`
	UID             int64   `json:"uid"`
	UserID          int     `json:"userId"`
	Name            string  `json:"name"`
	Barcode         string  `json:"barcode"`
	BuyPrice        float64 `json:"buyPrice"`
	SellPrice       float64 `json:"sellPrice"`
	Stock           float64 `json:"stock"`
	Pinyin          string  `json:"pinyin"`
	Enable          int     `json:"enable"`
	CreatedDatetime string  `json:"createdDatetime"`
}

//新增商品
//http://pospal.cn/openplatform/productapi.html#addProductInfo
func (a *API) AddProductInfo(productInfoParam *ProductInfoParam) (addProductInfoResult *AddProductInfoResult, err error) {
	mapP := map[string]interface{}{
		"name":        productInfoParam.ProductInfo.Name,
		"barcode":     productInfoParam.ProductInfo.Barcode,
		"buyPrice":    productInfoParam.ProductInfo.BuyPrice,
		"sellPrice":   productInfoParam.ProductInfo.SellPrice,
		"stock":       productInfoParam.ProductInfo.Stock,
		"categoryUid": productInfoParam.ProductInfo.CategoryUID,
	}
	result, err := a.AccessAPI("productOpenApi/addProductInfo", map[string]interface{}{
		"productInfo": mapP,
	})
	if err == nil {
		utils.Map2StructByJson(result["data"], &addProductInfoResult, false)
	}
	return addProductInfoResult, err
}

func IsErrSkuExist(err error) (isExist bool) {
	return utils.IsErrMatch(err, skuExistErrCode, []string{"商品已存在"})
}

func IsErrSkuNotExist(err error) (isExist bool) {
	return utils.IsErrMatch(err, skuNotExistErrCode, []string{"商品不存在"})
}

//修改商品
//http://pospal.cn/openplatform/productapi.html#addProductInfo
func (a *API) UpdateProductInfo(productInfo *ProductInfo) (err error) {
	mapP := map[string]interface{}{
		"uid": productInfo.UID,
	}
	if productInfo.BuyPrice != nil {
		mapP["buyPrice"] = productInfo.BuyPrice
	}
	if productInfo.SellPrice != nil {
		mapP["sellPrice"] = productInfo.SellPrice
	}
	if productInfo.Stock != nil {
		mapP["stock"] = productInfo.Stock
	}
	if productInfo.Enable != nil {
		mapP["enable"] = productInfo.Enable
	}
	if productInfo.IsCustomerDiscount != nil {
		mapP["isCustomerDiscount"] = productInfo.IsCustomerDiscount
	}
	if productInfo.CustomerPrice != nil {
		mapP["customerPrice"] = productInfo.CustomerPrice
	}
	_, err = a.AccessAPI("productOpenApi/updateProductInfo", map[string]interface{}{
		"productInfo": mapP,
	})
	return err
}

type QueryProductByBarcodeResult struct {
	UID             int64   `json:"uid"`
	Name            string  `json:"name"`
	Barcode         string  `json:"barcode"`
	BuyPrice        float64 `json:"buyPrice"`
	SellPrice       float64 `json:"sellPrice"`
	SellPrice2      float64 `json:"sellPrice2"`
	Stock           float64 `json:"stock"`
	MaxStock        float64 `json:"maxStock"`
	MinStock        float64 `json:"minStock"`
	Pinyin          string  `json:"pinyin"`
	Enable          int     `json:"enable"`
	CreatedDatetime string  `json:"createdDatetime"`
}

//按条形码查询商品（skuid）
//http://pospal.cn/openplatform/productapi.html#queryProductByBarcode
func (a *API) QueryProductByBarcode(barcode string) (queryProductByBarcodeResult *QueryProductByBarcodeResult, err error) {
	result, err := a.AccessAPI("productOpenApi/queryProductByBarcode", map[string]interface{}{
		"barcode": barcode,
	})
	if err == nil {
		utils.Map2StructByJson(result["data"], &queryProductByBarcodeResult, false)
	}
	return queryProductByBarcodeResult, err
}

//按条形码批量查询商品
//http://pospal.cn/openplatform/productapi.html#queryProductByBarcodes
func (a *API) QueryProductByBarcodes(barcodes []string) (queryProductByBarcodeResult []*QueryProductByBarcodeResult, err error) {
	result, err := a.AccessAPI("productOpenApi/queryProductByBarcodes", map[string]interface{}{
		"barcodes": barcodes,
	})
	if err == nil {
		utils.Map2StructByJson(result["data"], &queryProductByBarcodeResult, false)
	}
	return queryProductByBarcodeResult, err
}

type QueryProductImagesByBarcodeResult struct {
	ProductUID     int64  `json:"productUid"`
	ProductName    string `json:"productName"`
	ProductBarcode string `json:"productBarcode"`
	ImageURL       string `json:"imageUrl"`
}

//按条形码查询商品图片
//http://pospal.cn/openplatform/productapi.html#queryProductImagesByBarcode
func (a *API) QueryProductImagesByBarcode(barcode string) (queryProductImagesByBarcodeResult []*QueryProductImagesByBarcodeResult, err error) {
	result, err := a.AccessAPI("productOpenApi/queryProductImagesByBarcode", map[string]interface{}{
		"productBarcode": barcode,
	})
	if err == nil {
		utils.Map2StructByJson(result["data"], &queryProductImagesByBarcodeResult, false)
	}
	return queryProductImagesByBarcodeResult, err
}

type PostBackParameter struct {
	ParameterType  string `json:"parameterType"`
	ParameterValue string `json:"parameterType"`
}

type QueryProductPagesResult struct {
	PostBackParameter struct {
		ParameterType  string `json:"parameterType"`
		ParameterValue string `json:"parameterValue"`
	} `json:"postBackParameter"`
	Result []struct {
		UID                int64   `json:"uid"`
		CategoryUID        int     `json:"categoryUid,omitempty"`
		Name               string  `json:"name"`
		Barcode            string  `json:"barcode"`
		BuyPrice           float64 `json:"buyPrice"`
		SellPrice          float64 `json:"sellPrice"`
		SellPrice2         float64 `json:"sellPrice2"`
		Stock              float64 `json:"stock"`
		MaxStock           float64 `json:"maxStock"`
		MinStock           float64 `json:"minStock"`
		Pinyin             string  `json:"pinyin"`
		CustomerPrice      float64 `json:"customerPrice,omitempty"`
		IsCustomerDiscount int     `json:"isCustomerDiscount,omitempty"`
		SupplierUID        int     `json:"supplierUid,omitempty"`
		Enable             int     `json:"enable"`
		CreatedDatetime    string  `json:"createdDatetime"`
		UpdatedDatetime    string  `json:"updatedDatetime,omitempty"`
		Description        string  `json:"description,omitempty"`
		ProductionDate     string  `json:"productionDate,omitempty"`
		Attribute1         string  `json:"attribute1,omitempty"`
		Attribute2         string  `json:"attribute2,omitempty"`
		Attribute3         string  `json:"attribute3,omitempty"`
		Attribute4         string  `json:"attribute4,omitempty"`
		Attribute5         string  `json:"attribute5,omitempty"`
		Attribute6         string  `json:"attribute6,omitempty"`
		Attribute7         string  `json:"attribute7,omitempty"`
	} `json:"result"`
	PageSize int `json:"pageSize"`
}

//分页查询所有商品
//http://pospal.cn/openplatform/productapi.html#queryProductPages
func (a *API) QueryProductPages(postBackParameter *PostBackParameter) (queryProductPagesResult *QueryProductPagesResult, err error) {
	var mapP map[string]interface{}
	if postBackParameter != nil {
		mapP = map[string]interface{}{
			"parameterType":  postBackParameter.ParameterType,
			"parameterValue": postBackParameter.ParameterValue,
		}
	}
	result, err := a.AccessAPI("productOpenApi/queryProductPages", map[string]interface{}{
		"postBackParameter": mapP,
	})
	if err == nil {
		utils.Map2StructByJson(result["data"], &queryProductPagesResult, false)
	}
	return queryProductPagesResult, err
}
