package jdapi

import (
	"encoding/json"
	"errors"
	"fmt"

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

const (
	MaxStoreSkuBatchSize = 50
	MaxStockQty          = 100000000

	MaxAddByStoreAndSkusCount = 30 // 批量置顶商品排序接口的最大个数
)

type SkuPriceInfo struct {
	OutSkuId string `json:"outSkuId"`
	Price    int    `json:"price"`
}

type SkuStock struct {
	OutSkuId string `json:"outSkuId"`
	StockQty int    `json:"stockQty"`
}

type QueryStockRequest struct {
	StationNo string `json:"stationNo"`
	SkuId     int64  `json:"skuId"`
	DoSale    int    `json:"doSale"` //可售状态（0:可售，1:不可售）
}

type StockVendibility struct {
	OutSkuId string `json:"outSkuId"`
	DoSale   bool   `json:"doSale"` // 可售状态（true:可售，false:不可售）
}

type BaseStockCenterRequest struct {
	StationNo string `json:"stationNo"`
	SkuId     int64  `json:"skuId"`
}

type SkuIdEntity struct {
	OutSkuId string `json:"outSkuId"`
}

type StorePriceInfo struct {
	MarketPrice     int64  `json:"marketPrice"`
	Pin             string `json:"pin"`
	Price           int64  `json:"price"`
	PromoteVipPrice int64  `json:"promoteVipPrice"`
	SkuID           int64  `json:"skuId"`
	StationNo       string `json:"stationNo"`
	VenderID        string `json:"venderId"`
	VipPrice        int64  `json:"vipPrice"`
}

type QueryStockResponse struct {
	SkuID       int64  `json:"skuId"`
	StationNo   string `json:"stationNo"`
	UsableQty   int    `json:"usableQty"`
	LockQty     int    `json:"lockQty"`
	OrderQty    int    `json:"orderQty"`
	Vendibility int    `json:"vendibility"`
}

type UpdateVendibilityResponse struct {
	OutSkuID string `json:"outSkuId"`
	Code     int    `json:"code"`
	Msg      string `json:"msg"`

	SkuID       int64 `json:"skuId"`
	CurrentQty  int   `json:"currentQty"`
	LockQty     int   `json:"lockQty"`
	OrderQty    int   `json:"orderQty"`
	UsableQty   int   `json:"usableQty"`
	Vendibility int   `json:"vendibility"`
}

type StoreSkuBatchUpdateResponse struct {
	OutSkuID string `json:"outSkuId" json2:"outSkuId"`
	Code     string `json:"code" json2:"errorCode"` // 这个Code有可能返回19000B这种形式，只能当成字符串处理
	Msg      string `json:"msg" json2:"errorMessage"`

	// UpdateVendibility会返回以下字段
	SkuID       int64  `json:"skuId"`
	StationNo   string `json:"stationNo"`
	BusinessNo  int    `json:"businessNo"`
	CreatePin   string `json:"createPin"`
	StockQty    int    `json:"stockQty"`
	StockSource int    `json:"stockSource"`
	UpdatePin   string `json:"updatePin"`
	Vendibility int    `json:"vendibility"`
}

func IsCodeSuccess(code string) bool {
	return code == "" || code == "0"
}

// 传入为数组的，最多一次为50个
// 有好些功能有两个类似的函数，一个为到家ID，一个为商家ID，建议都只用商家ID的那个，因为：
// 1，这类函数一般可以批量操作
// 2，这类函数一般可以记录操作人员

// 根据商家商品编码和商家门店编码批量修改门店价格接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=205&apiid=fcbf346648a54d03b92dec8fa62ea643
func (a *API) UpdateVendorStationPrice(trackInfo string, outStationNo, stationNo string, skuPriceInfoList []*SkuPriceInfo) (responseList []*StoreSkuBatchUpdateResponse, err error) {
	jdParams := map[string]interface{}{
		"skuPriceInfoList": skuPriceInfoList,
	}
	if outStationNo != "" {
		jdParams["outStationNo"] = outStationNo
	} else {
		jdParams["stationNo"] = stationNo
	}
	result, err := a.AccessAPINoPage2("venderprice/updateStationPrice", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "0"), trackInfo)
	if result != nil {
		var err2 error
		if responseList, err2 = a.handleBatchOpResult(outStationNo, stationNo, len(skuPriceInfoList), err, result, "json2"); err2 != nil && err == nil {
			err = err2
		}
	}
	return responseList, err
}

// 根据到家商品编码和到家门店编码修改门店价格接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=205&apiid=45f83ef7c6e74dad94b6b68d3c50b673
// 单商品用此接口
func (a *API) UpdateStationPrice(trackInfo string, skuId int64, stationNo string, price int) (string, error) {
	jdParams := map[string]interface{}{
		"skuId":     skuId,
		"stationNo": stationNo,
		"price":     price,
	}
	result, err := a.AccessAPINoPage2("price/updateStationPrice", jdParams, nil, nil, nil, trackInfo)
	if err == nil && result != nil {
		return utils.Interface2String(result), nil
	}
	return "", err
}

// 根据到家商品编码和到家门店编码批量查询商品门店价格信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=205&apiid=21ccd5a00d3a4582b4c9a8ef0ae238fc
func (a *API) GetStationInfoList(stationNo string, skuIds []int64) (priceInfo []*StorePriceInfo, err error) {
	jdParams := map[string]interface{}{
		"skuIds":    skuIds,
		"stationNo": stationNo,
	}
	result, err := a.AccessAPINoPage("price/getStationInfoList", jdParams, nil, nil, genNoPageResultParser("code", "detail", "result", "0"))
	if err == nil && result != nil {
		err = JdMap2StructByJson(result, &priceInfo, false)
	}
	return priceInfo, err
}

func (a *API) handleBatchOpResult(outStationNo, stationNo string, batchCount int, inErr error, result interface{}, tagName string) (responseList []*StoreSkuBatchUpdateResponse, err error) {
	if result != nil {
		if err = utils.Map2Struct(result, &responseList, true, tagName, JavaDateHook); err == nil {
			var failedList []*StoreSkuBatchUpdateResponse
			for _, v := range responseList {
				if !IsCodeSuccess(v.Code) {
					failedList = append(failedList, v)
				}
			}
			var err2 *utils.ErrorWithCode
			if len(failedList) >= batchCount {
				err2 = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseCodeAccessFailed, 1) // 此错误基本用不到
			} else if len(failedList) > 0 { // 部分失败
				err2 = utils.NewErrorCode(string(utils.MustMarshal(failedList)), ResponseInnerCodePartialFailed, 1)
			}
			if err2 != nil {
				if stationNo != "" {
					err2.AddPrefixMsg(fmt.Sprintf("stationNo:%s", stationNo))
				} else if outStationNo != "" {
					err2.AddPrefixMsg(fmt.Sprintf("outStationNo:%s", outStationNo))
				}
				err = err2
			}
		}
	}
	return responseList, err
}

// 根据商家商品编码和商家门店编码批量修改现货库存接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=10812f9fc7ee4564b552f19270a7e92e
func (a *API) BatchUpdateCurrentQtys(trackInfo, outStationNo, stationNo string, skuStockList []*SkuStock, userPin string) (responseList []*StoreSkuBatchUpdateResponse, err error) {
	if (outStationNo == "" && stationNo == "") || (outStationNo != "" && stationNo != "") {
		return nil, errors.New("outStationNo and stationNo can not all be empty or have value")
	}
	jdParams := map[string]interface{}{
		"skuStockList": skuStockList,
		"userPin":      utils.GetAPIOperator(userPin),
	}
	if outStationNo != "" {
		jdParams["outStationNo"] = outStationNo
	} else {
		jdParams["stationNo"] = stationNo
	}
	result, err := a.AccessAPINoPage2("stock/batchUpdateCurrentQtys", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
	if result != nil {
		var err2 error
		if responseList, err2 = a.handleBatchOpResult(outStationNo, stationNo, len(skuStockList), err, result, ""); err2 != nil && err == nil {
			err = err2
		}
	}
	return responseList, err
}

// 根据商家商品编码和商家门店编码更新门店现货库存接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=a78664d4ead349da95d2f4576ed18d7f
// 此接口基本可以不用
func (a *API) StockUpdate(trackInfo string, outStationNo string, outSkuID string, currentQty int) error {
	// !这个接口的stationNo与skuId好像本身就写错了的
	jdParams := map[string]interface{}{
		"stationNo":  outStationNo,
		"skuId":      outSkuID,
		"currentQty": currentQty,
	}
	_, err := a.AccessAPINoPage2("stock/update", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "", "0"), trackInfo)
	if err == nil {
		return nil
	}
	return err
}

// 根据到家商品编码和到家门店编码更新门店现货库存
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=200&apiid=af70e699d4974e1683128742018f6381
// 单商品用此接口
func (a *API) UpdateCurrentQty(trackInfo string, stationNo string, skuID int64, currentQty int) error {
	jdParams := map[string]interface{}{
		"stationNo":  stationNo,
		"skuId":      skuID,
		"currentQty": currentQty,
	}
	_, err := a.AccessAPINoPage2("update/currentQty", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "", "0"), trackInfo)
	if err == nil {
		return nil
	}
	return err
}

// 根据到家商品编码和到家门店编码批量修改门店商品可售状态接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=b783a508e2cf4aca94681e4eed9af5bc
// 尽量不用这个接口，用下面那个，原因是这个不支持设置操作人，BatchUpdateVendibility可以
func (a *API) UpdateVendibility(trackInfo string, listBaseStockCenterRequest []*QueryStockRequest) (responseList []*StoreSkuBatchUpdateResponse, err error) {
	jdParams := map[string]interface{}{
		"listBaseStockCenterRequest": listBaseStockCenterRequest,
	}
	result, err := a.AccessAPINoPage2("stock/updateVendibility", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
	if result != nil {
		var err2 error
		if responseList, err2 = a.handleBatchOpResult("", listBaseStockCenterRequest[0].StationNo, len(listBaseStockCenterRequest), err, result, ""); err2 != nil && err == nil {
			err = err2
		}
	}
	return responseList, err
}

// 根据商家商品编码和门店编码批量修改门店商品可售状态接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=ac6f559ebabf4b70bc423687638e07c1
func (a *API) BatchUpdateVendibility(trackInfo, outStationNo, stationNo string, stockVendibilityList []*StockVendibility, userPin string) (responseList []*StoreSkuBatchUpdateResponse, err error) {
	if (outStationNo == "" && stationNo == "") || (outStationNo != "" && stationNo != "") {
		return nil, errors.New("outStationNo and stationNo can not all be empty or have value")
	}
	jdParams := map[string]interface{}{
		"stockVendibilityList": stockVendibilityList,
		"userPin":              utils.GetAPIOperator(userPin),
	}
	if outStationNo != "" {
		jdParams["outStationNo"] = outStationNo
	} else {
		jdParams["stationNo"] = stationNo
	}
	// 此函数在全部失败时，err仍然返回成功
	result, err := a.AccessAPINoPage2("stock/batchUpdateVendibility", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"), trackInfo)
	if result != nil {
		var err2 error
		if responseList, err2 = a.handleBatchOpResult(outStationNo, stationNo, len(stockVendibilityList), err, result, ""); err2 != nil && err == nil {
			err = err2
		}
	}
	return responseList, err
}

// 根据到家商品编码和门店编码批量查询商品库存及可售状态信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=bc6ad75e8fd34580856e06b5eb149aad
// 尽量不用这个接口，用下面那个
func (a *API) QueryOpenUseable(listBaseStockCenterRequest []*BaseStockCenterRequest) (stockResponse []*QueryStockResponse, err error) {
	jdParams := map[string]interface{}{
		"listBaseStockCenterRequest": listBaseStockCenterRequest,
	}
	result, err := a.AccessAPINoPage("stock/queryOpenUseable", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"))
	if err == nil && result != nil {
		err = JdMap2StructByJson(result, &stockResponse, false)
	}
	return stockResponse, err
}

// 根据商家商品编码和门店编码批量查询商品库存及可售状态信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=200&apiid=ba70316bb84f425f8c088d3c19b2570d
func (a *API) QueryStockCenter(outStationNo string, skuIds []*SkuIdEntity, userPin string) (vendibilityResponse []*UpdateVendibilityResponse, err error) {
	jdParams := map[string]interface{}{
		"outStationNo": outStationNo,
		"skuIds":       skuIds,
		"userPin":      utils.GetAPIOperator(userPin),
	}
	result, err := a.AccessAPINoPage("stock/queryStockCenter", jdParams, nil, nil, genNoPageResultParser("retCode", "retMsg", "data", "0"))
	if err == nil && result != nil {
		err = JdMap2StructByJson(result, &vendibilityResponse, false)
	}
	return vendibilityResponse, err
}

// 批量置顶商品排序接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=a7677f1a75984ed3a6ea3d4827f5a6b4
func (a *API) AddByStoreAndSkus(stationNo int64, skuIDs []int64) (err error) {
	jdParams := map[string]interface{}{
		"storeId": stationNo,
		"skuIds":  skuIDs,
	}
	_, err = a.AccessAPINoPage("OrgSortService/addByStoreAndSkus", jdParams, nil, nil, genNoPageResultParser("status", "message", "", "200"))
	return err
}

// 删除门店商品会员价接口
// https://openo2o.jddj.com/staticnew/widgets/resources.html?groupid=205&apiid=73116e2b9f374814880f1272ba301fdf
func (a *API) DelVipPrice(outStationNo string, skuIds []*SkuIdEntity) (err error) {
	jdParams := map[string]interface{}{
		"outStationNo":     outStationNo,
		"skuPriceInfoList": skuIds,
	}
	_, err = a.AccessAPINoPage("vender/delVipPrice", jdParams, nil, nil, genNoPageResultParser("code", "msg", "", "0"))
	return err
}

// 	AuerySkuInfoList 查询已经上传的商品列表
func (a *API) AuerySkuInfoList(pageNo, pageSize int64, searchAfterSkuId string) ([]string, int64, error) {
	jdParams := map[string]interface{}{
		//"pageNo":   pageNo,
		"pageSize": pageSize,
		//"isFilterDel": "0",
	}
	if searchAfterSkuId != "" {
		jdParams["searchAfterSkuId"] = searchAfterSkuId
	}
	data, err := a.AccessAPINoPage("pms/querySkuInfoList", jdParams, nil, nil, genNoPageResultParser("code", "msg", "result", "0"))
	if data == nil {
		return nil, 0, err
	}
	skuList := data.(map[string]interface{})["result"]
	if skuList == nil {
		return nil, 0, nil
	}
	sku := make([]*JDSkuList, 0, 0)
	json.Unmarshal([]byte(skuList.(string)), &sku)

	skuId := make([]string, 0, 0)
	for _, list := range sku {
		if list.OutSkuId != "" {
			skuId = append(skuId, list.OutSkuId)
		}
	}
	afterSkuId, _ := data.(map[string]interface{})["searchAfterSkuId"].(json.Number).Int64()
	return skuId, afterSkuId, err
}

type JDSkuList struct {
	SkuId              int64         `json:"skuId"`
	OutSkuId           string        `json:"outSkuId"`
	OrgCode            int           `json:"orgCode"`
	CategoryId         int           `json:"categoryId"`
	BrandId            int           `json:"brandId"`
	SkuName            string        `json:"skuName"`
	Slogan             string        `json:"slogan"`
	SkuPrice           int           `json:"skuPrice"`
	StockNum           int           `json:"stockNum"`
	Weight             float64       `json:"weight"`
	ProductLocation    string        `json:"productLocation"`
	Producter          string        `json:"producter"`
	UpcCode            string        `json:"upcCode"`
	FixedUpTime        string        `json:"fixedUpTime,omitempty"`
	FixedDownTime      string        `json:"fixedDownTime"`
	FixedStatus        int           `json:"fixedStatus"`
	ShopCategories     []int         `json:"shopCategories"`
	PriceUnit          string        `json:"priceUnit"`
	PrefixKey          string        `json:"prefixKey"`
	SuffixKey          string        `json:"suffixKey"`
	IsBreakable        int           `json:"isBreakable,omitempty"`
	LiquidStatue       string        `json:"liquidStatue,omitempty"`
	Prescripition      string        `json:"prescripition,omitempty"`
	HighSingularValue  string        `json:"highSingularValue,omitempty"`
	BusinessMark       []interface{} `json:"businessMark,omitempty"`
	SellCities         []int         `json:"sellCities"`
	PackageFee         float64       `json:"packageFee"`
	SuperName          string        `json:"superName"`
	SaleAttrValueId    string        `json:"saleAttrValueId"`
	SaleAttrValueName  string        `json:"saleAttrValueName"`
	SloganStartTime    string        `json:"sloganStartTime,omitempty"`
	SloganEndTime      string        `json:"sloganEndTime,omitempty"`
	Length             int           `json:"length,omitempty"`
	Wide               int           `json:"wide,omitempty"`
	High               int           `json:"high,omitempty"`
	TransportAttribute string        `json:"transportAttribute,omitempty"`
	FixedType          int           `json:"fixedType,omitempty"`
	SuperId            int           `json:"superId,omitempty"`
}

// UnBindStoreGoods 解绑商品
func (a *API) UnBindStoreGoods(skuId int64) {
	jdParams := map[string]interface{}{
		"skuId":     skuId,
		"stationNo": "23988364",
		"opPin":     "liulei",
	}
	_, err := a.AccessAPINoPage("StoreGoodsPlatformService/unBindStoreGoods", jdParams, nil, nil, genNoPageResultParser("code", "msg", "data", "0"))
	if err != nil {
		return
	}
}
