package mtwmapi

import (
	"encoding/json"
	"git.rosy.net.cn/baseapi/utils"
	"regexp"
	"strings"
)

const (
	MaxSkuNameCharCount = 30 // SkuName的最大字符数

	MaxStoreSkuBatchSize  = 200 // retail/sku/stock, retail/sku/sellStatus和retail/sku/price这些批量操作的最大值
	MaxRetailListPageSize = 200
	MaxBatchDeleteSize    = 100 // retailCat/batchdelete/catandretail这个接口的批量最大值
)

const (
	SellStatusOnline  = 0 // 上架
	SellStatusOffline = 1 // 下架

	SpecialAttrBrand    = "1200000088" //属性id，取值范围仅支持两个：1200000088-品牌, 1200000094-产地
	SpecialAttrProducer = "1200000094"
	SpecialAttrOrigin   = "1200000132" // 产地

	TypeCategory     = 1 //1-类目，2-类目属性 不传默认1
	TypeCategoryAttr = 2

	NeedYes = "1" //1-必传,2-非必传
)

const ( // {"attrId":1200000275,"attrName":"是否有机","valueList":[{"valueId":1300005199,"value":"非有机"}]},
	MtwmSkuAttr200002727 = `[{"attrId":1200000088,"attrName":"品牌","valueList":[{"valueId":1000001,"value":"其他品牌"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000210,"attrName":"商品类别","valueList":[{"valueId":1300025224,"value":"水果混合果切/果拼"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]},{"attrId":1200004449,"attrName":"拼数","valueList":[{"valueId":1300015654,"value":"单拼"}]}]`
	MtwmSkuAttr200001555 = `[{"attrId":1200000088,"attrName":"品牌","valueList":[{"valueId":1002998,"value":"伊利"}]},{"attrId":1200000210,"attrName":"商品类别","valueList":[{"valueId":1300001219,"value":"冰激凌"}]}]`
	MtwmSkuAttr200002728 = `[{"attrId":1200000088,"attrName":"品牌","valueList":[{"valueId":1000001,"value":"其他品牌"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]},{"attrId":1200000210,"attrName":"商品类别","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
	//200001519
	MtwmSkuAttr200000592 = `[{"attrId":1200000088,"attrName":"品牌","valueList":[{"valueId":1000001,"value":"其他品牌"}]}]`
	//200002704
	MtwmSkuAttr200002731 = `[{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
	MtwmSkuAttr200002716 = `[{"attrId":1200000287,"attrName":"特产品种","valueList":[{"valueId":1300016304,"value":"其他"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
	//200002667，200002713
	MtwmSkuAttr200002670 = `[{"attrId":1200000202,"attrName":"品种","valueList":[{"valueId":1300000249,"value":"其他"}]},{"attrId":1200000287,"attrName":"特产品种","valueList":[{"valueId":1300016304,"value":"其他"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
	//MtwmSkuAttr200002680 = `[{"attrId":1200000289,"attrName":"品规","valueList":[{"valueId":1300004255,"value":"未区分品规"}]},{"attrId":1200000202,"attrName":"品种","valueList":[{"valueId":1300000249,"value":"其他"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
	MtwmSkuAttr200002680 = `[{"attrId":1200004607,"attrName":"水果形态","valueList":[{"valueId":1300017364,"value":"新鲜整果"}]},{"attrId":1200004608,"attrName":"单果重量","valueList":[{"valueId":1300017449,"value":"约4.5kg~5kg"}]},{"attrId":1200000202,"attrName":"品种","valueList":[{"valueId":1300000249,"value":"其他"}]},{"attrId":1200000094,"attrName":"产地","valueList":[{"valueId":100000050,"value":"中国"}]},{"attrId":1200000132,"attrName":"国产/进口","valueList":[{"valueId":1300000003,"value":"国产"}]},{"attrId":1200000286,"attrName":"果品品牌","valueList":[{"valueId":1300000249,"value":"其他"}]}]`
)

var (
	retailBatchFailedSkuReg = regexp.MustCompile(`((?:\d+;)+)`)
)

type RetailCategoryInfo struct {
	Name     string                `json:"name"`
	Code     string                `json:"code"`
	Sequence int                   `json:"sequence"`
	Level    int                   `json:"level"`
	Children []*RetailCategoryInfo `json:"children"`
}

type RetailTag struct {
	ID       int64  `json:"id"`
	Name     string `json:"name"`
	Level    int    `json:"level"`
	NamePath string `json:"namePath"`
}

type BareStoreSkuInfo struct {
	SkuID string `json:"sku_id"`
	Price string `json:"price,omitempty"`
	Stock string `json:"stock,omitempty"`
}

type BareStoreFoodInfo struct {
	AppFoodCode string              `json:"app_food_code"`
	Skus        []*BareStoreSkuInfo `json:"skus,omitempty"`
}

type AvailableTimesInfo struct {
	Friday    string `json:"friday"`
	Monday    string `json:"monday"`
	Saturday  string `json:"saturday"`
	Sunday    string `json:"sunday"`
	Thursday  string `json:"thursday"`
	Tuesday   string `json:"tuesday"`
	Wednesday string `json:"wednesday"`
}

type SkuInfo struct {
	AvailableTimes        *AvailableTimesInfo `json:"available_times"`
	BoxNum                string              `json:"box_num"`
	BoxPrice              string              `json:"box_price"`
	IsSellFlag            int                 `json:"isSellFlag"`
	LadderBoxNum          string              `json:"ladder_box_num"`
	LadderBoxPrice        string              `json:"ladder_box_price"`
	LimitOpenSyncStockNow bool                `json:"limit_open_sync_stock_now"`
	LocationCode          string              `json:"location_code"`
	MinOrderCount         string              `json:"min_order_count"`
	Price                 string              `json:"price"`
	SkuId                 string              `json:"sku_id"`
	Spec                  string              `json:"spec"`
	Stock                 string              `json:"stock"`
	Unit                  string              `json:"unit"`
	Upc                   string              `json:"upc"`
	Weight                string              `json:"weight"`
	//WeightForUnit string `json:"weight_for_unit"` //  weight weight_for_unit 至多填写一个
	//WeightUnit    string `json:"weight_unit"`
}

type AppFood struct {
	AppFoodCode           string     `json:"app_food_code"`
	AppPoiCode            string     `json:"app_poi_code"`
	BoxNum                float64    `json:"box_num"`
	BoxPrice              float64    `json:"box_price"`
	CategoryCode          string     `json:"category_code"`
	CategoryName          string     `json:"category_name"`
	Ctime                 int        `json:"ctime"`
	Description           string     `json:"description"`
	IsSp                  int        `json:"isSp"`
	IsSoldOut             int        `json:"is_sold_out"`
	IsSpecialty           int        `json:"is_specialty"`
	MinOrderCount         int        `json:"min_order_count"`
	Name                  string     `json:"name"`
	Picture               string     `json:"picture"`
	PictureList           []string   `json:"pictureList"`
	PictureContents       string     `json:"picture_contents"`
	Price                 float64    `json:"price"`
	SecondaryCategoryCode string     `json:"secondary_category_code"`
	SecondaryCategoryName string     `json:"secondary_category_name"`
	Sequence              int        `json:"sequence"`
	UpcCode               string     `json:"upc_code"`
	Skus                  string     `json:"skus"`
	SkuList               []*SkuInfo `json:"skuList"`
	TagID                 int        `json:"tag_id"`
	Unit                  string     `json:"unit"`
	Utime                 int        `json:"utime"`
	ZhName                string     `json:"zh_name"`
	CommonAttrValue       string     `json:"common_attr_value"`
}

type AppFoodResult struct {
	AppFoodCode string `json:"app_food_code"`
	ErrorMsg    string `json:"error_msg"`
}

type AppFoodResult4SellStatus struct {
	AppFoodCode string `json:"app_food_code"` // 印象里一开始是appFoodCode，还专门问过美团（https://developer.waimai.meituan.com/home/myquestionDetail/6566），但现在这个又变成app_food_code了。。。
	Msg         string `json:"msg"`
}

type Param4UpdateCat struct {
	CategoryCodeOrigin    string `json:"category_code_origin,omitempty"`
	CategoryNameOrigin    string `json:"category_name_origin,omitempty"`
	CategoryCode          string `json:"category_code,omitempty"`
	SecondaryCategoryCode string `json:"secondary_category_code,omitempty"`
	SecondaryCategoryName string `json:"secondary_category_name,omitempty"`
	Sequence              int    `json:"sequence,omitempty"`
	TargetLevel           string `json:"target_level,omitempty"`
	TargetParentName      string `json:"target_parent_name,omitempty"`

	TopFlag   string `json:"top_flag,omitempty"`
	WeeksTime string `json:"weeks_time,omitempty"`
	Period    string `json:"period,omitempty"`
}

type CategoryAttrListResult struct {
	AttrID        string `json:"attr_id"`
	AttrName      string `json:"attr_name"`
	AttrValueType string `json:"attr_value_type"`
	Need          string `json:"need"`
	CharacterType string `json:"character_type"`
	TextMaxLength string `json:"text_max_length"`
	Sequence      int    `json:"sequence"`
	SupportExtend string `json:"support_extend"`
	ValueList     []struct {
		ValueID string `json:"value_id"`
		Value   string `json:"value"`
	} `json:"value_list"`
}

// 美团分类没有ID，就以名字为唯一标识，不论级别都必须不能重名
// name（和originName）的长度不能超过10个字符（字符，不是字节）
// 创建一级分类，originName为空，name为新分类名，secondaryName为空
// 修改一级分类，originName为分类名，name为分类新名，secondaryName为空
// 创建二级分类，secondaryName为二级分类名，
// 		（如果originName为空，同时创建一级分类，所以如果只是创建二级分类，originName与name要填一样的，此时sequence指的二级分类的sequence，一级分类的sequence为缺省值）
// 修改二级分类，originName为二级分类名，name为二级分类新名，secondaryName为空
// https://developer.waimai.meituan.com/home/docDetail/71
// https://developer.waimai.meituan.com/home/questionDetail/4669
// 此接口并发访问，可能导致创建相同的分类，见如下问题回复
// https://developer.waimai.meituan.com/home/myquestionDetail/6931
func (a *API) RetailCatUpdate(poiCode, catName string, updateParams *Param4UpdateCat) (err error) {
	if updateParams != nil {
		if updateParams.CategoryCodeOrigin != "" {
			updateParams.CategoryNameOrigin = ""
		}
	}
	params := utils.Struct2MapByJson(updateParams)
	params[KeyAppPoiCode] = poiCode
	params["category_name"] = catName
	_, err = a.AccessAPI("retailCat/update", false, params)

	return err
}

// 删除商品分类
// 当分类下存在子级分类或商品时，不允许直接删除此分类。
func (a *API) RetailCatDelete(poiCode, code, name string, moveProductToUncate int) (err error) {
	params := map[string]interface{}{
		KeyAppPoiCode: poiCode,
	}
	if code != "" {
		params["category_code"] = code
	} else {
		params["category_name"] = name
	}
	if moveProductToUncate != 0 {
		params["move_product_to_uncate"] = 1 // 分类存在商品时将商品转移到未分类当中
	}

	_, err = a.AccessAPI("retailCat/delete", false, params)

	return err
}

func (a *API) RetailCatList(poiCode string) (retailCatList []*RetailCategoryInfo, err error) {
	result, err := a.AccessAPI("retailCat/list", true, map[string]interface{}{
		KeyAppPoiCode: poiCode,
	})
	if err == nil {
		return interface2CatList(result, 1, nil), nil
	}
	return nil, err
}

// offset 从0开始，limit最大不能超过200
// 返回的app_poi_code始终是空，手动建的商品app_food_code也为空（导致无法通过API删除）
func (a *API) RetailList(poiCode string, offset, limit int) (foodList []*AppFood, err error) {
	result, err := a.AccessAPI("retail/list", true, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"offset":      offset,
		"limit":       limit,
	})
	if err == nil {
		if err = utils.Map2StructByJson(result, &foodList, true); err == nil {
			for _, food := range foodList {
				utils.UnmarshalUseNumber([]byte(food.Skus), &food.SkuList)
				food.PictureList = strings.Split(food.Picture, ",")
			}
		}
	}
	return foodList, err
}

func (a *API) RetailListAll(poiCode string, offset int) (foodList []*AppFood, err error) {
	data := make([]*AppFood, 0, 0)
	offset = offset * GeneralMaxLimit
	batchList, err2 := a.RetailList(poiCode, offset, GeneralMaxLimit) // GeneralMaxLimit
	if err = err2; err == nil {
		data = append(data, batchList...)
	}
	return data, err
}

func handleRetailBatchResult(result interface{}) (failedFoodList []*AppFoodResult, err error) {
	if msg, ok := result.(string); ok && msg != "" {
		err = utils.UnmarshalUseNumber([]byte(msg), &failedFoodList)
	}
	return failedFoodList, err
}

func handleRetailBatchResultByRegexp(result interface{}) (failedFoodList []*AppFoodResult, err error) {
	if msg, ok := result.(string); ok && msg != "" {
		findList := retailBatchFailedSkuReg.FindStringSubmatch(msg)
		if len(findList) == 2 {
			ids := strings.Split(strings.Trim(findList[1], ";"), ";")
			if len(ids) > 0 {
				failedFoodList = make([]*AppFoodResult, len(ids))
				for k, v := range ids {
					failedFoodList[k] = &AppFoodResult{
						AppFoodCode: v,
						ErrorMsg:    "",
					}
				}
			}
		}
	}
	return failedFoodList, err
}

// 商品名最长30个字符（非字节）
// 此函数可能创建相同foodCode的商品，如下问题的回复中有提到
// https://developer.waimai.meituan.com/home/myquestionDetail/6716
// 另外这个接口即使不指定operate_type为1，也可能报错：”商品spu名称在该店内分类中已存在“，原因就是已经存在两个相同的SKU了
func (a *API) RetailInitData(trackInfo, poiCode, foodCode string, params map[string]interface{}) (err error) {
	_, err = a.AccessAPI2("retail/initdata", false, utils.MergeMaps(map[string]interface{}{
		KeyAppPoiCode:  poiCode,
		KeyAppFoodCode: foodCode,
	}, params), resultKeyData, trackInfo)
	return err
}

// 这个创建加更新
func (a *API) RetailBatchInitData(trackInfo, poiCode string, foodDataList []map[string]interface{}) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/batchinitdata", false, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"food_data":   string(utils.MustMarshal(foodDataList)),
	}, resultKeyMsg, trackInfo)

	if err == nil {
		failedFoodList, err = handleRetailBatchResult(result)
	}
	return failedFoodList, err
}

// RetailBatchInitData2 这个只更新打包费
func (a *API) RetailBatchInitData2(trackInfo, poiCode string, foodDataList []map[string]interface{}) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/batchinitdata", false, map[string]interface{}{
		KeyAppPoiCode:  poiCode,
		"food_data":    string(utils.MustMarshal(foodDataList)),
		"operate_type": 2,
	}, resultKeyMsg, trackInfo)
	if err == nil {
		failedFoodList, err = handleRetailBatchResult(result)
	}

	return failedFoodList, err
}

func (a *API) RetailSkuPrice(trackInfo, poiCode string, foodData []*BareStoreFoodInfo) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/sku/price", false, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"food_data":   string(utils.MustMarshal(foodData)),
	}, resultKeyMsg, trackInfo)
	if err == nil {
		failedFoodList, err = handleRetailBatchResult(result)
	}
	return failedFoodList, err
}

func (a *API) RetailSkuStock(trackInfo, poiCode string, foodData []*BareStoreFoodInfo) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/sku/stock", false, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"food_data":   string(utils.MustMarshal(foodData)),
	}, resultKeyMsg, trackInfo)
	if err == nil {
		failedFoodList, err = handleRetailBatchResult(result)
	}
	return failedFoodList, err
}

// retail/sku/sellStatus在部分失败时会返回错误，其它相应的批处理函数则会返回成功
// 此接口已准备废弃
// 2019年9月17日开放平台已上线新接口【retail/sellStatus】，用于零售类商家批量更新商品售卖状态。请已接入老接口（retail/sku/sellStatus）的开发者在2019年10月31日前完成接口迁移，使用新接口的请求地址https://waimaiopen.meituan.com/api/v1/retail/sellStatus。
// 开放平台将于2019年11月1日开始全面下线老接口（retail/sku/sellStatus），如开发者逾期未完成接口迁移，调用老接口失败所造成的相关问题或损失由商家自行承担。
//func (a *API) RetailSkuSellStatus(trackInfo, poiCode string, foodData []*BareStoreFoodInfo, sellStatus int) (failedFoodList []*AppFoodResult, err error) {
//	_, err = a.AccessAPI2("retail/sku/sellStatus", false, map[string]interface{}{
//		KeyAppPoiCode: poiCode,
//		"food_data":   string(utils.MustMarshal(foodData)),
//		"sell_status": sellStatus,
//	}, resultKeyMsg, trackInfo)
//	if err != nil {
//		if errExt, ok := err.(*utils.ErrorWithCode); ok {
//			failedFoodList, _ = handleRetailBatchResultByRegexp(errExt.ErrMsg())
//		}
//	}
//	return failedFoodList, err
//}

// 此接口部分失败也返回成功，但错误消息格式（errorMsg, appFoodCode）与其它两个不一样
func (a *API) RetailSellStatus(trackInfo, poiCode string, foodData []*BareStoreFoodInfo, sellStatus int) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/sellStatus", false, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"food_data":   string(utils.MustMarshal(foodData)),
		"sell_status": sellStatus,
	}, resultKeyMsg, trackInfo)
	if err == nil {
		var tmpFailedFoodList []*AppFoodResult4SellStatus
		if msg, ok := result.(string); ok && msg != "" {
			if err = utils.UnmarshalUseNumber([]byte(msg), &tmpFailedFoodList); err == nil {
				for _, v := range tmpFailedFoodList {
					failedFoodList = append(failedFoodList, &AppFoodResult{
						AppFoodCode: v.AppFoodCode,
						ErrorMsg:    v.Msg,
					})
				}
			}
		}
	}
	return failedFoodList, err
}

// 此接口部分失败也返回成功，但错误消息格式（errorMsg, appFoodCode）与其它两个不一样
func (a *API) RetailSellStatus2(trackInfo, poiCode string, foodData []map[string]string, sellStatus int) (failedFoodList []*AppFoodResult, err error) {
	result, err := a.AccessAPI2("retail/sellStatus", false, map[string]interface{}{
		KeyAppPoiCode: poiCode,
		"food_data":   foodData,
		"sell_status": sellStatus,
	}, resultKeyMsg, trackInfo)
	if err == nil {
		var tmpFailedFoodList []*AppFoodResult4SellStatus
		if msg, ok := result.(string); ok && msg != "" {
			if err = utils.UnmarshalUseNumber([]byte(msg), &tmpFailedFoodList); err == nil {
				for _, v := range tmpFailedFoodList {
					failedFoodList = append(failedFoodList, &AppFoodResult{
						AppFoodCode: v.AppFoodCode,
						ErrorMsg:    v.Msg,
					})
				}
			}
		}
	}
	return failedFoodList, err
}

func (a *API) RetailGet(poiCode, foodCode string) (food *AppFood, err error) {
	result, err := a.AccessAPI("retail/get", true, map[string]interface{}{
		KeyAppPoiCode:  poiCode,
		KeyAppFoodCode: foodCode,
	})
	if err == nil {
		if err = utils.Map2StructByJson(result, &food, true); err == nil && food.Skus != "" {
			utils.UnmarshalUseNumber([]byte(food.Skus), &food.SkuList)
			food.PictureList = strings.Split(food.Picture, ",")
		}
	}
	return food, err
}

func (a *API) RetailSkuSave(poiCode, foodCode string, standardSkus, unstandardSkus []map[string]interface{}) (err error) {
	_, err = a.AccessAPI("retail/sku/save", false, map[string]interface{}{
		KeyAppPoiCode:     poiCode,
		KeyAppFoodCode:    foodCode,
		"standard_skus":   string(utils.MustMarshal(standardSkus)),
		"unstandard_skus": string(utils.MustMarshal(unstandardSkus)),
	})
	return err
}

// RetailDelete 根据APP方门店id和商品id，删除商品。
func (a *API) RetailDelete(trackInfo, poiCode, foodCode string) (err error) {
	_, err = a.AccessAPI2("retail/delete", false, map[string]interface{}{
		KeyAppPoiCode:          poiCode,
		KeyAppFoodCode:         foodCode,
		"is_delete_retail_cat": 1,
	}, resultKeyData, trackInfo)
	return err
}

func (a *API) RetailSkuDelete(trackInfo, poiCode, foodCode, skuID string) (err error) {
	_, err = a.AccessAPI2("retail/sku/delete", false, map[string]interface{}{
		KeyAppPoiCode:  poiCode,
		KeyAppFoodCode: foodCode,
		"sku_id":       skuID,
	}, resultKeyData, trackInfo)
	return err
}

// CategoryAttrList 根据末级类目id获取类目属性列表
//https://open-shangou.meituan.com/home/docDetail/386
func (a *API) CategoryAttrList(tagId int64) (categoryAttrListResult []*CategoryAttrListResult, err error) {
	result, err := a.AccessAPI("gw/category/attr/list", true, map[string]interface{}{
		"tag_id": tagId,
	})
	if err == nil && result != nil {
		utils.Map2StructByJson(result.(map[string]interface{})["general_attrs"], &categoryAttrListResult, false)
	}
	return categoryAttrListResult, err
}

type CategoryAttrValueListResult struct {
	ValueID string `json:"value_id"`
	Value   string `json:"value"`
}

// RetailProductRules 根据末级美团分类ID获取图片发布规则
func (a *API) RetailProductRules(tagID int64) (*ProductRulesObj, error) {
	result, err := a.AccessAPI2("retail/product/rules", true, map[string]interface{}{
		"tag_id": tagID,
	}, "success_map", "")
	if err != nil {
		return nil, err
	}

	rules := &ProductRulesObj{}
	if result != nil {
		resultByte, _ := json.Marshal(result)
		err = utils.UnmarshalUseNumber(resultByte, rules)
		if err != nil {
			return nil, err
		}
	}
	return rules, err
}

type ProductRulesObj struct {
	StructRules []struct {
		RuleId    int    `json:"rule_id"`
		RuleName  string `json:"rule_name"`
		ValueList []struct {
			IsByDefault bool   `json:"is_by_default"`
			ValueId     int    `json:"value_id"`
			ValueName   string `json:"value_name"`
		} `json:"value_list"`
	} `json:"struct_rules"`
	UnstructRules struct {
		QualificationPicturesRule struct {
			IsQualificationPicturesNeed int `json:"is_qualification_pictures_need"`
		} `json:"qualification_pictures_rule"`
		SpecialPicturesRules []struct {
			IsDisplayed               int    `json:"is_displayed"`
			IsRequired                int    `json:"is_required"`
			NumLimit                  int    `json:"num_limit"`
			SpecialPictureDescription string `json:"special_picture_description"`
			SpecialPictureExample     string `json:"special_picture_example"`
			SpecialPictureTitle       string `json:"special_picture_title"`
			SpecialPictureType        int    `json:"special_picture_type"`
		} `json:"special_pictures_rules"`
	} `json:"unstruct_rules"`
}

//category/attr/value/list 查询特殊属性的属性值列表
//https://open-shangou.meituan.com/home/docDetail/387
func (a *API) CategoryAttrValueList(attr_id int64, keyword string) (categoryAttrValueListResult []*CategoryAttrValueListResult, err error) {
	result, err := a.AccessAPI("gw/category/attr/value/list", true, map[string]interface{}{
		"attr_id":       attr_id,
		"keyword":       keyword,
		"page_num":      1,
		"page_size":     20,
		"category_type": 1,
	})
	if err == nil {
		utils.Map2StructByJson(result, &categoryAttrValueListResult, false)
	}
	return categoryAttrValueListResult, err
}

type RetailRecommendTagResp struct {
	UpcCode       string         `json:"upc_code"`        //条形码编号 如类目匹配失败，返回null
	Name          string         `json:"name"`            //商品名称 如类目匹配失败，返回null
	TagID         int            `json:"tag_id"`          //美团内部类目id
	WeightForUnit float64        `json:"weight_for_unit"` //重量值
	WeightUnit    string         `json:"weight_unit"`     // 表示sku的重量数值单位，枚举值如下： 1."克(g)" 2."千克(kg)" 3."毫升(ml)" 4."升(L)" 5."磅" 6."斤" 7."两"。
	GeneralAttrs  []GeneralAttrs `json:"general_attrs"`
}

type GeneralAttrs struct {
	AttrID    string      `json:"attr_id"`   //属性id
	AttrName  string      `json:"attr_name"` //属性名称
	ValueList []ValueList `json:"value_list"`
}
type ValueList struct {
	ValueID string `json:"value_id"` //属性值id
	Value   string `json:"value"`    //属性值
}

// RetailRecommendTag 根据商品UPC或商品名称或类目ID查询平台推荐类目及类目属性信息
func (a *API) RetailRecommendTag(name, appPoiCode string, tagID, tagType int) (retVal *RetailRecommendTagResp, err error) {
	result, err := a.AccessAPI("retail/recommend/tag", true, map[string]interface{}{
		"name":         name,
		"app_poi_code": appPoiCode,
		"tag_id":       tagID,
		"type":         tagType,
	})
	if err == nil {
		if err = utils.Map2StructByJson(result, &retVal, false); err == nil {
			return retVal, nil
		}
	}
	return nil, err
}

// 就是厂商商品类别
func (a *API) RetailGetSpTagIds() (tagIds []*RetailTag, err error) {
	result, err := a.AccessAPI("retail/getSpTagIds", true, nil)
	if err == nil {
		if err = utils.Map2StructByJson(result, &tagIds, false); err == nil {
			return tagIds, nil
		}
	}
	return nil, err
}

// 此接口将申请授权后方可接入
func (a *API) RetailCatSkuBatchDelete(trackInfo, poiCode string, catNames []string, secondaryCatNames []string, foodCodes []string) (err error) {
	params := map[string]interface{}{
		KeyAppPoiCode: poiCode,
	}
	if len(catNames) > 0 {
		params["category_names"] = strings.Join(catNames, ",")
	}
	if len(secondaryCatNames) > 0 {
		params["secondary_category_names"] = strings.Join(secondaryCatNames, ",")
	}
	if len(foodCodes) > 0 {
		params["app_food_codes"] = strings.Join(foodCodes, ",")
	}
	_, err = a.AccessAPI2("retailCat/batchdelete/catandretail", false, params, resultKeyData, trackInfo)
	return err
}

// 批量删除商品分类及商品
// https://developer.waimai.meituan.com/home/docDetail/286
func (a *API) RetailCatSkuBatchDelete2(trackInfo, poiCode string, catCodes, catNames, secondaryCatCodes, secondaryCatNames, foodCodes []string) (err error) {
	params := map[string]interface{}{
		KeyAppPoiCode: poiCode,
	}
	if len(catCodes) > 0 {
		params["category_codes"] = strings.Join(catCodes, ",")
	} else if len(catNames) > 0 {
		params["category_names"] = strings.Join(catNames, ",")
	}

	if len(secondaryCatCodes) > 0 {
		params["secondary_category_codes"] = strings.Join(secondaryCatCodes, ",")
	} else if len(secondaryCatNames) > 0 {
		params["secondary_category_names"] = strings.Join(secondaryCatNames, ",")
	}

	if len(foodCodes) > 0 {
		params["app_food_codes"] = strings.Join(foodCodes, ",")
	}
	_, err = a.AccessAPI2("retailCat/batchdelete/catandretail", false, params, resultKeyData, trackInfo)
	return err
}

type SpuData struct {
	AppSpuCode    string `json:"app_spu_code"`   //商家中台系统里商品的编码
	SkuID         string `json:"sku_id"`         //SKU码(商家的规格编码)
	PurchasePrice string `json:"purchase_price"` //商品进货价
}

// https://opendj.meituan.com/home/docDetail/821
//  【代运营】批量更新商品进货价 /retail/purchase/price/update
func (a *API) BatchSetRestockingPrice(trackInfo, appPoiCode string, spuData []*SpuData) error {
	_, err := a.AccessAPI2("/retail/purchase/price/update", false, map[string]interface{}{
		KeyAppPoiCode: appPoiCode,
		"spu_data":    string(utils.MustMarshal(spuData)),
	}, resultKeyMsg, trackInfo)
	return err
}

// 私有辅助函数
func interface2Cat(data interface{}, level int) (cat *RetailCategoryInfo) {
	mapData, ok := data.(map[string]interface{})
	if ok {
		cat = &RetailCategoryInfo{
			Name:     utils.Interface2String(mapData["name"]),
			Code:     utils.Interface2String(mapData["code"]),
			Sequence: int(utils.Interface2Int64WithDefault(mapData["sequence"], 0)),
			Level:    level,
		}
		children := mapData["children"]
		if children != nil {
			cat.Children = interface2CatList(children, level+1, nil)
		}
	}
	return cat
}

func interface2CatList(data interface{}, level int, interface2CatHandler func(data interface{}, level int) (cat *RetailCategoryInfo)) (cats []*RetailCategoryInfo) {
	if interface2CatHandler == nil {
		interface2CatHandler = interface2Cat
	}
	maps, ok := data.([]interface{})
	if ok {
		cats = make([]*RetailCategoryInfo, len(maps))
		for index, v := range maps {
			cats[index] = interface2CatHandler(v, level)
		}
	}
	return cats
}

func IsErrCategoryExist(err error) (isExist bool) {
	return utils.IsErrMatch(err, utils.Int2Str(ErrCodeSkuCategoryExist), nil)
}

func IsErrCategoryNotExist(err error) (isNotExist bool) {
	return utils.IsErrMatch(err, utils.Int2Str(ErrCodeSkuCategoryNotExist), nil) ||
		utils.IsErrMatch(err, utils.Int2Str(ErrCodeParameterFormatWrong), []string{
			"门店内不存在该分类",
		})
}

func IsErrSkuNotExist(err error) (isExist bool) {
	return utils.IsErrMatch(err, utils.Int2Str(ErrCodeNoAppFood), nil)
}
