package jdapi

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

const (
	KeyBrandId            = "brandId"
	KeyBrandName          = "brandName"
	KeyBrandStatus        = "brandStatus"
	KeyCategoryId         = "categoryId"
	KeyChildIds           = "childIds"
	KeyFields             = "fields"
	KeyFixedStatus        = "fixedStatus"
	KeyHandleStatus       = "handleStatus"
	KeyHeight             = "height"
	KeyID                 = "id"
	KeyImages             = "images"
	KeyImgType            = "imgType"
	KeyIfViewDesc         = "ifViewDesc"
	KeyIsFilterDel        = "isFilterDel"
	KeyIsSale             = "isSale"
	KeyKeyValue           = "keyValue"
	KeyLength             = "length"
	KeyLiquidStatue       = "liquidStatue"
	KeyOutSkuId           = "outSkuId"
	KeyOutSpuId           = "outSuperId"
	KeySpuName            = "superName"
	KeySkuMainInfo        = "skuMainInfo"
	KeyPID                = "pid"
	KeyProductDesc        = "productDesc"
	KeyPageNo             = "pageNo"
	KeyPageSize           = "pageSize"
	KeyPrefixKey          = "prefixKey"
	KeyPrefixKeyId        = "prefixKeyId"
	KeyPreKeyEndTime      = "preKeyEndTime"
	KeyPreKeyStartTime    = "preKeyStartTime"
	KeyPrescripition      = "prescripition"
	KeyShopCategoryLevel  = "shopCategoryLevel"
	KeyShopCategoryName   = "shopCategoryName"
	KeyShopCategories     = "shopCategories"
	KeySellCities         = "sellCities"
	KeySlogan             = "slogan"
	KeySloganEndTime      = "sloganEndTime"
	KeySloganStartTime    = "sloganStartTime"
	KeySort               = "sort"
	KeySkuId              = "skuId"
	KeySkuName            = "skuName"
	KeySkuPrice           = "skuPrice"
	KeyStoreId            = "storeId"
	KeySystemFixedStatus  = "systemFixedStatus"
	KeyTransportAttribute = "transportAttribute"
	KeyUpcCode            = "upcCode"
	KeyWeight             = "weight"
)

const (
	FakeKeySpecAttr = "specAttr"
)

const (
	MaxBatchSize4BatchUpdateOutSkuId = 50
	MaxPageSize4QuerySku             = 50
	MaxSkuIDsCount4QueryListBySkuIds = 25

	ErrMustUPC = "处方药商品请根据商品UPC码批量新增商品接口创建"
)

const (
	SkuFixedStatusOnline  = 1 // 上架
	SkuFixedStatusOffline = 2 // 下架
	SkuFixedStatusDeleted = 4 // 删除
)

const (
	CreateSpuResultSuccess    = 1
	CreateSpuResultInProgress = 2
	CreateSpuResultFailed     = 3
)

const (
	IsFilterDelTrue = "0" // 0代表不查已删除商品
)

const (
	MaxSkuNameCharCount = 45 // skuname最长字符数
	SaleAttrIDBase      = 1001
	SaleAttrValueIDBase = 10
)

const (
	ImgTypeMain   = 1 // 商品图片
	ImgTypeDetail = 2 // 详情图片
)

type SkuIDPair struct {
	SkuId    int64  `json:"skuId"`
	OutSkuId string `json:"outSkuId"`
}

type BatchUpdateOutSkuIdFailedItem struct {
	Detail  string     `json:"detail"`
	SkuInfo *SkuIDPair `json:"skuInfo"`
}

type BrandInfo struct {
	ID          int    `json:"id"`
	BrandName   string `json:"brandName"`
	BrandStatus int    `json:"brandStatus"`
}

type IDKeyValuePair struct {
	ID       string `json:"_id"`
	KeyValue string `json:"keyValue"`
}

type ProductStatus struct {
	Synchronized  bool                   `json:"synchronized"`
	EsEntity      map[string]interface{} `json:"esEntity"`
	ProductEntity map[string]interface{} `json:"productEntity"`
}

// 这个类型商家店内分类与到家分类共用，
type CategoryInfo struct {
	Id       int64  `json:"id"`
	ParentId int64  `json:"pid"`
	Name     string `json:"categoryName"`
	Level    int    `json:"categoryLevel"`
	Sort     int    `json:"sort"`     // 店内分类独有
	Status   int    `json:"status"`   // 到家分类独有
	FullPath string `json:"fullPath"` // 到家分类独有
}

type CreateByUpcParam struct {
	UniqueUpc      string `json:"uniqueCode"`     // 商品UPC码
	OutSku         string `json:"outSku"`         // 商家商品编码，商家系统中唯一编码，限1-35字符，与到家商品编码一对一对应
	JdPrice        string `json:"jdPrice"`        // 商家商品价格(单位：元)，用于初始商品门店价格，所有的商品门店价格都会初始化成该值。后续修改商品门店价格需要通过价格类接口修改。
	ShopCategoryID int64  `json:"shopCategoryId"` // 商家店内分类编码，店内分类编码通过查询商家店内分类信息接口获取
	IsSale         bool   `json:"isSale"`         // 门店商品可售状态，true为可售，false为不可售，默认为可售。
}

type CreateByUpcParam2 struct {
	Upc            string `json:"upc"`            // 商品UPC码
	OutSkuId       string `json:"outSkuId"`       // 商家商品编码，商家系统中唯一编码，限1-35字符，与到家商品编码一对一对应
	JdPrice        string `json:"jdPrice"`        // 商家商品价格(单位：元)，用于初始商品门店价格，所有的商品门店价格都会初始化成该值。后续修改商品门店价格需要通过价格类接口修改。
	ShopCategoryID int64  `json:"shopCategoryId"` // 商家店内分类编码，店内分类编码通过查询商家店内分类信息接口获取
	IsSale         bool   `json:"isSale"`         // 门店商品可售状态，true为可售，false为不可售，默认为可售。
}

type CreateByUpcPair struct {
	Upc   string
	SkuId int64
}

type QuerySkuParam struct {
	SkuName     string `json:"skuName,omitempty"`
	UpcCode     string `json:"upcCode,omitempty"`
	SkuID       int64  `json:"skuId,omitempty"`
	IsFilterDel string `json:"isFilterDel,omitempty"` // 是否查询出已删除的上传商品(0代表不查已删除商品,不填则查出全部商品)
	PageNo      int    `json:"pageNo,omitempty"`
	PageSize    int    `json:"pageSize,omitempty"`
}

type SkuMain struct {
	SuperID        int64   `json:"superId"`
	SkuID          int64   `json:"skuId"`
	OutSkuID       string  `json:"outSkuId"`
	CategoryID     int64   `json:"categoryId"`
	BrandID        int64   `json:"brandId"`
	ShopCategories []int64 `json:"shopCategories"`
	SkuName        string  `json:"skuName"`
	Slogan         string  `json:"slogan"`
	FixedStatus    int     `json:"fixedStatus"` // 商家商品上下架状态(1:上架;2:下架;4:删除;)
	FixedUpTime    string  `json:"fixedUpTime"`
	OrgCode        int     `json:"orgCode"`
	SellCities     []int64 `json:"sellCities"`
	SkuPrice       int     `json:"skuPrice"`
	Weight         float64 `json:"weight"`
}

const (
	IsSaleYes = 1
	IsSaleNo  = -1
)

type OpSkuParam struct {
	TraceID                        string   `json:"traceId"`
	OutSkuID                       string   `json:"outSkuId"`
	ShopCategories                 []int64  `json:"shopCategories,omitempty"`
	CategoryID                     int64    `json:"categoryId,omitempty"`
	BrandID                        int64    `json:"brandId,omitempty"`
	SkuName                        string   `json:"skuName,omitempty"`
	SkuPrice                       int      `json:"skuPrice,omitempty"`
	Weight                         float64  `json:"weight,omitempty"`
	FixedStatus                    int      `json:"fixedStatus,omitempty"` // 商家商品上下架状态(1:上架;2:下架;4:删除;)
	IsSale                         int      `json:"-"`                     // 创建：0,1可售，-1不可售，更新：0忽略，1可售，-1不可售
	DontUseThisFieldDirectlyIsSale bool     `json:"isSale"`                // 门店商品可售状态(true/false)；新建商品时，如果为true，门店商品可售状态初始为可售，如果为false， 门店商品可售状态初始为不可售。后续修改各个门店商品可售状态时，请使用根据京东到家商品编码批量修改门店商品可售状态接口。
	Upc                            string   `json:"upcCode,omitempty"`     // TODO 老版与新版接口参数不一致，UPC编码（商品条码），限1-35个字符，包装类的商品要求UPC编码必填，且要符合条码编写的校验，否则商品会不予通过，接口返回错误状态码code为10059。
	Images                         []string `json:"images,omitempty"`
	ProductDesc                    string   `json:"productDesc,omitempty"`
	IfViewDesc                     int      `json:"ifViewDesc"`
	Slogan                         string   `json:"slogan,omitempty"`
	SloganStartTime                string   `json:"sloganStartTime,omitempty"`
	SloganEndTime                  string   `json:"sloganEndTime,omitempty"`
	SellCities                     []int64  `json:"sellCities,omitempty"`
}

type QueryListBySkuIdsParam struct {
	SkuIDs       []int64 `json:"skuIds"`
	ImgType      int     `json:"imgType,omitempty"`
	HandleStatus []int   `json:"handleStatus,omitempty"`
}

type ImgHandleQueryResult struct {
	ID              string `json:"id"`
	SkuID           int64  `json:"skuId"`
	IsMain          int    `json:"isMain"`
	ImgType         int    `json:"imgType"`
	SourceImgURL    string `json:"sourceImgUrl"`
	SkuImgSort      int    `json:"skuImgSort"`
	HandleStatus    int    `json:"handleStatus"`
	HandleStatusStr string `json:"handleStatusStr"`
	HandleRemark    string `json:"handleRemark"`
	HandleErrLog    string `json:"handleErrLog"`
}

var (
	skuExistReg = regexp.MustCompile(`商家skuId已存在:(\d+)`)
)

// 分页查询商品品牌信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=1ca07a3e767649a7a44fc6ea7e9ed8dd
func (a *API) QueryPageBrandInfo(pageNo, pageSize int, brandId int64, brandName string) (brandList []*BrandInfo, totalCount int, err error) {
	if pageNo <= 0 {
		pageNo = 1
	}
	if pageSize == 0 {
		pageSize = 50
	}
	params := map[string]interface{}{
		KeyPageNo:   pageNo, // pageNo好像必须要有值，否则一直不返回
		KeyPageSize: pageSize,
		KeyFields: []string{
			"BRAND_ID",
			"BRAND_NAME",
			"BRAND_STATUS",
		},
	}
	if brandId != 0 {
		params[KeyBrandId] = brandId
	}
	if brandName != "" {
		params[KeyBrandName] = brandName
	}

	result, totalCount, err := a.AccessAPIHavePage("pms/queryPageBrandInfo", params, nil, nil, nil)
	if err == nil {
		brandList = make([]*BrandInfo, len(result))
		for index, v := range result {
			mapData := v.(map[string]interface{})
			brandList[index] = &BrandInfo{
				ID:          int(utils.MustInterface2Int64(mapData[KeyID])),
				BrandName:   utils.Interface2String(mapData[KeyBrandName]),
				BrandStatus: int(utils.MustInterface2Int64(mapData[KeyBrandStatus])),
			}
		}
		return brandList, totalCount, nil
	}
	return nil, 0, err
}

// 获取京东到家类目信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=d287d326124d42c090cff03c16385706
func (a *API) QueryChildCategoriesForOP(pid int64) (catList []*CategoryInfo, err error) {
	result, err := a.AccessAPINoPage("api/queryChildCategoriesForOP", utils.Params2Map("fields", []string{
		"ID",
		"PID",
		"CATEGORY_NAME",
		"CATEGORY_LEVEL",
		"CATEGORY_STATUS",
		"FULLPATH",
	}, "id", pid), nil, nil, nil)
	if err == nil {
		return interface2CatList(result, 1, func(data interface{}, level int) (cat *CategoryInfo) {
			mapData, ok := data.(map[string]interface{})
			if ok {
				cat = &CategoryInfo{
					Id:       utils.MustInterface2Int64(mapData["id"]),
					ParentId: utils.MustInterface2Int64(mapData["pid"]),
					Name:     utils.Interface2String(mapData["categoryName"]),
					Level:    int(utils.MustInterface2Int64(mapData["categoryLevel"])),
					Status:   int(utils.MustInterface2Int64(mapData["categoryStatus"])),
					FullPath: utils.Interface2String(mapData["fullPath"]),
				}
			}
			return cat
		}), nil
	}
	return nil, err
}

// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=de26f24a62aa47a49e5ab7579d638cb3
func (a *API) AddShopCategory(pid int64, shopCategoryName string, shopCategoryLevel, sort int, userName string) (catId string, err error) {
	params := map[string]interface{}{
		KeyPID:              pid,
		KeyShopCategoryName: shopCategoryName,
	}
	if shopCategoryLevel > 0 {
		params[KeyShopCategoryLevel] = shopCategoryLevel
	}
	if sort >= 0 {
		params[KeySort] = sort
	}
	if userName != "" {
		params["createPin"] = utils.GetAPIOperator(userName)
	}
	result, err := a.AccessAPINoPage("pms/addShopCategory", params, nil, nil, nil)
	if err == nil {
		return (result.(map[string]interface{}))["id"].(string), nil
	}
	return "", err
}

// 查询商家店内分类信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=964f2d248a7e42b196be2ab35b4e93b4
func (a *API) QueryCategoriesByOrgCode() (catList []*CategoryInfo, err error) {
	result, err := a.AccessAPINoPage("pms/queryCategoriesByOrgCode", utils.Params2Map("fields", []string{
		"ID",
		"PID",
		"SHOP_CATEGORY_NAME",
		"SHOP_CATEGORY_LEVEL",
		"SORT",
	}), nil, nil, nil)
	if err == nil {
		return interface2CatList(result, 1, nil), nil
	}
	return nil, err
}

// 修改商家店内分类信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=1de278c670b64da492f676ab78d62f73
func (a *API) UpdateShopCategory(id int64, shopCategoryName string) error {
	params := map[string]interface{}{
		KeyID:               id,
		KeyShopCategoryName: shopCategoryName,
	}
	_, err := a.AccessAPINoPage("pms/updateShopCategory", params, nil, nil, nullResultParser)
	if IsErrIgnorable(err) {
		err = nil
	}
	return err
}

func IsErrIgnorable(err error) bool {
	return err == nil || utils.IsErrMatch(err, "-3", []string{"店内分类名称未修改，无需操作"})
}

// 修改商家店内分类顺序接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=2a8267602e814be9828f0c7ce307b872
func (a *API) ChangeShopCategoryOrder(pid int64, childIds []int64) error {
	params := map[string]interface{}{
		KeyPID:      pid,
		KeyChildIds: childIds,
	}
	_, err := a.AccessAPINoPage("pms/changeShopCategoryOrder", params, nil, nil, nullResultParser)
	return err
}

// 删除商家店内分类接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=c17b96e9fe254b2a8574f6d1bc0c1667
// 删除一个不存在的分类，好像不会报错
func (a *API) DelShopCategory(id int64) error {
	_, err := a.AccessAPINoPage("pms/delShopCategory", utils.Params2Map(KeyID, id), nil, nil, nullResultParser)
	return err
}

// 新增商品信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=dfe6a5ca73fa421da1c9f969b848113e
func (a *API) AddSku(outSkuId string, cagtegoryId int, shopCategories []int64, brandId int, skuName string, skuPrice int, weight float32, images []string, fixedStatus int, isSale bool, addParams map[string]interface{}) (skuId string, err error) {
	fixedParams := map[string]interface{}{
		KeyOutSkuId:       outSkuId,
		KeyCategoryId:     cagtegoryId,
		KeyShopCategories: shopCategories,
		KeyBrandId:        brandId,
		KeySkuName:        skuName,
		KeySkuPrice:       skuPrice,
		KeyWeight:         weight,
		KeyImages:         images,
		KeyFixedStatus:    fixedStatus,
		KeyIsSale:         isSale,
	}
	result, err := a.AccessAPINoPage("pms/sku/addSku", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
	if err == nil {
		return (result.(map[string]interface{}))["skuId"].(string), nil
	}
	return "", err
}

func translateIsSale(isSale int) bool {
	return isSale == 0 || isSale == IsSaleYes
}

func (a *API) AddSku2(param *OpSkuParam) (skuID string, err error) {
	param.DontUseThisFieldDirectlyIsSale = translateIsSale(param.IsSale)
	mapData := utils.Struct2MapByJson(param)
	result, err := a.AccessAPINoPage("pms/sku/addSku", mapData, nil, nil, nil)
	if err == nil {
		return (result.(map[string]interface{}))["skuId"].(string), nil
	}
	return "", err
}

func (a *API) NewAddSku(param *NewAddSkuParam) (skuID string, err error) {
	mapData := utils.Struct2MapByJson(param)
	result, err := a.AccessAPINoPage("pms/addSku", mapData, nil, nil, nil)
	if err == nil {
		skuId := utils.Interface2Int64WithDefault(result.(map[string]interface{})["skuId"], 0)
		return utils.Int64ToStr(skuId), nil
	}
	return "", err
}

func (a *API) NewAddSku222(param map[string]interface{}) (skuID string, err error) {
	result, err := a.AccessAPINoPage("pms/addSku", param, nil, nil, nil)
	if err == nil {
		skuId := utils.Interface2Int64WithDefault(result.(map[string]interface{})["skuId"], 0)
		return utils.Int64ToStr(skuId), nil
	}
	return "", err
}

type NewAddSkuParam struct {
	//LimitPurchaseNum int      `json:"limitPurchaseNum"`
	TraceId        string   `json:"traceId"`
	OutSkuId       string   `json:"outSkuId"`
	ShopCategories []int64  `json:"shopCategories"`
	CategoryId     int64    `json:"categoryId"`
	BrandId        int64    `json:"brandId"`
	SkuName        string   `json:"skuName"`
	SkuPrice       int64    `json:"skuPrice"`
	Weight         float64  `json:"weight"`
	Upc            string   `json:"upc"`
	Images         []string `json:"images"`
	ProductDesc    string   `json:"productDesc"`
	//IfViewDesc       int      `json:"ifViewDesc"`
	//Slogan           string   `json:"slogan"`
	//SloganStartTime       time.Time   `json:"sloganStartTime"`
	//SloganEndTime         time.Time   `json:"sloganEndTime"`
	//PrefixKeyId string `json:"prefixKeyId"`
	//PrefixKey   string `json:"prefixKey"`
	//PreKeyStartTime       time.Time   `json:"preKeyStartTime"`
	//PreKeyEndTime         time.Time   `json:"preKeyEndTime"`
	//Length             int    `json:"length"`
	//Width              int    `json:"width"`
	//Height             int    `json:"height"`
	//TransportAttribute string `json:"transportAttribute"`
	//LiquidStatue       string `json:"liquidStatue"`
	//Prescripition      string `json:"prescripition"`
	//HighSingularValue  string `json:"highSingularValue"`
	//IsBreakable        string `json:"isBreakable"`
	FixedStatus int  `json:"fixedStatus"`
	IsSale      bool `json:"isSale"`
	//SellCities         []int64 `json:"sellCities"`
	//PackageFee float64 `json:"packageFee"`
	//BusinessMark       []int   `json:"businessMark"`
	//ReturnLabel string `json:"returnLabel"`
	//RegistImage string `json:"registImage"`
	//ApprovalTime          time.Time   `json:"approvalTime"`
	//EndTime               time.Time   `json:"endTime"`
	//CategoryAttrs         interface{} `json:"categoryAttrs"`
	//SalePointList         interface{} `json:"salePointList"`
	//StationShopCategories interface{} `json:"stationShopCategories"`
	//OutStationNos         interface{} `json:"outStationNos"`
}

// 根据商家商品编码修改商品信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=290bdb0ea8a44e10b86b05591254ad68
func (a *API) UpdateSku(outSkuId string, params map[string]interface{}) (skuId string, err error) {
	result, err := a.AccessAPINoPage("pms/sku/updateSku", utils.MergeMaps(params, utils.Params2Map("outSkuId", outSkuId)), nil, nil, nil)
	if err == nil {
		return (result.(map[string]interface{}))["skuId"].(string), nil
	}
	return "", err
}

func (a *API) UpdateSku2(param *OpSkuParam) (skuID string, err error) {
	param.DontUseThisFieldDirectlyIsSale = translateIsSale(param.IsSale)
	mapData := utils.Struct2MapByJson(param)
	result, err := a.AccessAPINoPage("pms/sku/updateSku", mapData, nil, nil, nil)
	if err == nil {
		return (result.(map[string]interface{}))["skuId"].(string), nil
	}
	return "", err
}

// 根据到家商品编码批量更新商家商品编码接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=4155d29bbdf649b69c67473b705ce7e7
func (a *API) BatchUpdateOutSkuId(skuInfoList []*SkuIDPair) (failedList []*BatchUpdateOutSkuIdFailedItem, err error) {
	result, err := a.AccessAPINoPage("pms/sku/batchUpdateOutSkuId", utils.Params2Map("skuInfoList", skuInfoList), nil, nil, nil)
	err2 := utils.Map2StructByJson(result, &failedList, false)
	if err == nil {
		err = err2
	}
	return failedList, err
}

// 查询商家已上传商品信息列表接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=e433b95f74524dab91718432c0358977
// pageNo 从1开始
func (a *API) QuerySkuInfos(queryParam *QuerySkuParam) (skuList []*SkuMain, totalCount int, err error) {
	if queryParam.PageNo <= 0 {
		queryParam.PageNo = 1
	}
	if queryParam.PageSize == 0 {
		queryParam.PageSize = MaxPageSize4QuerySku
	}
	result, totalCount, err := a.AccessAPIHavePage("pms/querySkuInfos", utils.Struct2MapByJson(queryParam), nil, nil, nil)
	if err == nil {
		err = JdMap2StructByJson(result, &skuList, false)
	}
	return skuList, totalCount, err
}

// 查询商品图片处理结果接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=17506653e03542f9a49023711780c30d
func (a *API) QueryListBySkuIds(queryParam *QueryListBySkuIdsParam) (imgList []*ImgHandleQueryResult, err error) {
	result, err := a.AccessAPINoPage("order/queryListBySkuIds", utils.Struct2MapByJson(queryParam), nil, nil, nil)
	if err == nil {
		err = JdMap2StructByJson(result, &imgList, false)
	}
	return imgList, err
}

// 分页查询京东到家商品前缀库接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=2195b87baf0c4783bb1a4fda35aea7d1
func (a *API) QueryKeyWordDicInfo(pageNo, pageSize int, keyValue string) (values []*IDKeyValuePair, totalCount int, err error) {
	if pageNo <= 0 {
		pageNo = 1
	}
	if pageSize == 0 {
		pageSize = 50
	}
	params := map[string]interface{}{
		KeyPageNo:   pageNo, // pageNo好像必须要有值，否则一直不返回
		KeyPageSize: pageSize,
		KeyFields: []string{
			"ID",
			"KEYVALUE",
		},
	}
	if keyValue != "" {
		params[KeyKeyValue] = keyValue
	}

	result, totalCount, err := a.AccessAPIHavePage("pms/queryKeyWordDicInfo", params, nil, nil, nil)
	if err == nil {
		values = make([]*IDKeyValuePair, len(result))
		for index, v := range result {
			mapData := v.(map[string]interface{})
			values[index] = &IDKeyValuePair{
				ID:       utils.Interface2String(mapData["_id"]),
				KeyValue: utils.Interface2String(mapData[KeyKeyValue]),
			}
		}
		return values, totalCount, nil
	}
	return nil, 0, err
}

// 商家商品状态同步接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=5e29d6c9317847e58b8cbcc70702fd52
func (a *API) SyncProduct(storeId, skuId string) (retVal bool, err error) {
	result, err := a.AccessAPINoPage("search/syncProduct", utils.Params2Map(KeyStoreId, storeId, KeySkuId, skuId), nil, nil, genNoPageResultParser("status", "message", "synchronized", "200"))
	if err == nil {
		return result.(bool), nil
	}
	return false, err
}

// 商家商品状态检查接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=a348122182ef459982cae1280407ff17
func (a *API) GetProductStatus(storeId, skuId string) (retVal *ProductStatus, err error) {
	result, err := a.AccessAPINoPage("search/getProductStatus", utils.Params2Map(KeyStoreId, storeId, KeySkuId, skuId), nil, nil, func(data map[string]interface{}) (interface{}, error) {
		status := utils.MustInterface2Int64(data["status"])
		if status == 200 {
			return &ProductStatus{
				Synchronized:  data["synchronized"].(bool),
				EsEntity:      data["esEntity"].(map[string]interface{}),
				ProductEntity: data["productEntity"].(map[string]interface{}),
			}, nil
		}
		return nil, utils.NewErrorIntCode(data["message"].(string), int(status))
	})
	if err == nil {
		return result.(*ProductStatus), nil
	}
	return nil, err

}

// 新增SPU信息接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=e30936da75294e55bcfdabb92c3815bc
func (a *API) AddSpu(outSpuId string, cagtegoryId int, shopCategories []int64, brandId int, spuName string, images []string, fixedStatus int, addParams map[string]interface{}, skus []map[string]interface{}) (spuId int64, skuPairs []*SkuIDPair, err error) {
	attrList := []string{}
	for k, v := range skus {
		attr := v[FakeKeySpecAttr].(string) //getSkuAttr(v[KeyWeight].(float32))
		attrList = append(attrList, attr)
		skus[k] = utils.MergeMaps(map[string]interface{}{
			"saleAttrValues": genAttrMapList(attr),
		}, v)
		delete(skus[k], FakeKeySpecAttr)
	}
	fixedParams := map[string]interface{}{
		KeyOutSpuId:       outSpuId,
		KeyCategoryId:     cagtegoryId,
		KeyShopCategories: shopCategories,
		KeyBrandId:        brandId,
		KeySpuName:        spuName,
		KeyImages:         images,
		KeyFixedStatus:    fixedStatus,
		KeySkuMainInfo:    skus,
		KeyProductDesc:    spuName, // todo
		"saleAttrRelationInfoList": []map[string]interface{}{
			map[string]interface{}{
				"saleAttrName":          "规格",
				"saleAttrValueNameList": attrList,
			},
		},
	}
	result, err := a.AccessAPINoPage("pms/addSpu", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
	if err == nil {
		resultMap := result.(map[string]interface{})
		skuMainParterResponseList := resultMap["skuMainParterResponseList"].([]interface{})
		skuPairs = make([]*SkuIDPair, len(skuMainParterResponseList))
		for k, v := range skuMainParterResponseList {
			v2 := v.(map[string]interface{})
			skuPairs[k] = &SkuIDPair{
				OutSkuId: v2["outSkuId"].(string),
				SkuId:    utils.Str2Int64(v2["skuId"].(string)),
			}
		}
		return utils.MustInterface2Int64(resultMap["superId"]), skuPairs, nil
	}
	return 0, nil, err
}

// 追加新的SKU到指定的SPU接口
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=cffb839b06f042b28d6397b6bd4f2676
func (a *API) AppendSku(outSpuId string, outSkuId string, skuName string, skuPrice int, weight float32, images []string, fixedStatus int, isSale bool, specAttr string, addParams map[string]interface{}) (skuID int64, err error) {
	attr := specAttr //getSkuAttr(weight)
	if err = a.AppendSpuSaleAttr(outSpuId, utils.Int2Str(SaleAttrIDBase), attr); err != nil {
		return 0, err
	}

	fixedParams := map[string]interface{}{
		KeyOutSpuId:      outSpuId,
		KeyOutSkuId:      outSkuId,
		KeySkuName:       skuName,
		KeySkuPrice:      skuPrice,
		KeyWeight:        weight,
		KeyImages:        images,
		KeyFixedStatus:   fixedStatus,
		KeyIsSale:        isSale,
		"saleAttrValues": genAttrMapList(attr),
	}
	result, err := a.AccessAPINoPage("pms/appendSku", utils.MergeMaps(fixedParams, addParams), nil, nil, nil)
	if err == nil {
		resultMap := result.(map[string]interface{})
		skuMainParterResponseList := resultMap["skuMainParterResponseList"].([]interface{})
		return utils.Str2Int64(skuMainParterResponseList[0].(map[string]interface{})["skuId"].(string)), nil
	}
	return 0, err
}

// 更新SPU基础信息,不可以更新销售属性
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=3816c5eadc5d4f268f760cac14483ec0
func (a *API) UpdateSpu(outSpuId string, params map[string]interface{}) (err error) {
	_, err = a.AccessAPINoPage("pms/updateSpu", utils.MergeMaps(params, utils.Params2Map(KeyOutSpuId, outSpuId)), nil, nil, nil)
	return err
}

// 更新SPU下指定SKU的基础信息
// https://opendj.jd.com/staticnew/widgets/resources.html?groupid=180&apiid=8be2b5d153044179a13089e7f19e24e6
func (a *API) UpdateSkuBaseInfo(outSpuId, outSkuId string, params map[string]interface{}) (err error) {
	_, err = a.AccessAPINoPage("pms/updateSkuBaseInfo", utils.MergeMaps(params, utils.Params2Map(KeyOutSpuId, outSpuId, KeyOutSkuId, outSkuId)), nil, nil, nil)
	return err
}

func (a *API) GetSkuSaleAttrName() (saleAttrNameList []string, err error) {
	result, err := a.AccessAPINoPage("pms/getSkuSaleAttrName", nil, nil, nil, nil)
	if err == nil {
		return utils.Slice2StringSlice(result.([]interface{})), nil
	}
	return nil, err

}

func (a *API) AppendSpuSaleAttr(outSpuId, attrName, attrNewValue string) (err error) {
	_, err = a.AccessAPINoPage("pms/appendSpuSaleAttr", map[string]interface{}{
		KeyOutSpuId:         outSpuId,
		"saleAttrId":        attrName,
		"saleAttrValueName": attrNewValue,
	}, nil, nil, nil)
	return err
}

func (a *API) GetSpuSaleAttr(outSpuId string) (attrList []map[string]interface{}, err error) {
	result, err := a.AccessAPINoPage("pms/getSpuSaleAttr", map[string]interface{}{
		KeyOutSpuId: outSpuId,
	}, nil, nil, nil)
	if err == nil {
		return utils.Slice2MapSlice(result.([]interface{})), nil
	}
	return nil, err
}

func (a *API) BatchAddSku(batchSkuRequestList []*CreateByUpcParam) (pairs []*CreateByUpcPair, err error) {
	result, err := a.AccessAPINoPage("PmsSkuMainService/batchAddSku", map[string]interface{}{
		"batchSkuRequestList": batchSkuRequestList,
	}, nil, nil, genNoPageResultParser("code", "result", "detail", "0"))
	if err == nil {
		// todo 这个API在找不到UPC创建失败时，code也是0，底层不能判断失败
		if result2, ok := result.([]interface{}); ok && len(result2) > 0 {
			detail := utils.Slice2MapSlice(result2)
			pairs = make([]*CreateByUpcPair, len(detail))
			for k, v := range detail {
				pairs[k] = &CreateByUpcPair{
					Upc:   utils.Interface2String(v["uniqueCode"]),
					SkuId: utils.MustInterface2Int64(v["skuId"]),
				}
			}
			return pairs, nil
		} else {
			return nil, utils.NewErrorIntCode("BatchAddSku失败", -1)
		}
	}
	return nil, err
}

type BatchAddSkuByUPCResult struct {
	FailedDetail string `json:"failedDetail"`
	OrgCode      string `json:"orgCode"`
	OutSkuID     string `json:"outSkuId"`
	ResultCode   string `json:"resultCode"`
	ResultMsg    string `json:"resultMsg"`
	SkuID        string `json:"skuId"`
	UpcCode      string `json:"upcCode"`
}

func (a *API) BatchAddSkuByUPC(batchSkuRequestList []*CreateByUpcParam2) (batchAddSkuByUPCResult *BatchAddSkuByUPCResult, err error) {
	result, err := a.AccessAPINoPage("pms/batchAddSku", map[string]interface{}{
		"traceId":                 utils.GetUUID(),
		"openBatchAddSkuRequests": batchSkuRequestList,
	}, nil, nil, nil)
	if err == nil {
		utils.Map2StructByJson(result.([]interface{})[0].(map[string]interface{}), &batchAddSkuByUPCResult, false)
		if batchAddSkuByUPCResult.SkuID == "" && batchAddSkuByUPCResult.FailedDetail != "" {
			return nil, fmt.Errorf(batchAddSkuByUPCResult.FailedDetail)
		}
	}
	return batchAddSkuByUPCResult, err
}

func (a *API) GetSpuStatus(outSpuId string) (resultStatus int, err error) {
	result, err := a.AccessAPINoPage("pms/getSpuStatus", map[string]interface{}{
		"outSuperId": outSpuId,
	}, nil, nil, nil)
	if err == nil {
		return int(utils.MustInterface2Int64(result.(map[string]interface{})["status"])), nil
	}
	return 0, err
}

func (a *API) GetSkuStatus(outSkuId string) (resultStatus int, err error) {
	result, err := a.AccessAPINoPage("pms/getSkuStatus", map[string]interface{}{
		"outSkuId": outSkuId,
		"traceId":  utils.GetUUID(),
	}, nil, nil, nil)
	if err == nil {
		return int(utils.MustInterface2Int64(result.(map[string]interface{})["resultMsg"])), nil
	}
	return 0, err
}

func (a *API) UpdateSpuSaleAttr(outSpuId, saleAttrId, saleAttrName, saleAttrValueId, saleAttrValueName string) (err error) {
	apiParams := map[string]interface{}{
		"outSuperId":      outSpuId,
		"saleAttrId":      saleAttrId,
		"saleAttrValueId": saleAttrValueId,
	}
	if saleAttrName != "" {
		apiParams["saleAttrName"] = saleAttrName
	}
	if saleAttrValueName != "" {
		apiParams["saleAttrValueName"] = saleAttrValueName
	}
	_, err = a.AccessAPINoPage("pms/updateSpuSaleAttr", apiParams, nil, nil, nil)
	return err
}

///////////////////////////
// 私有辅助函数
func interface2Cat(data interface{}, level int) (cat *CategoryInfo) {
	mapData, ok := data.(map[string]interface{})
	if ok {
		cat = &CategoryInfo{
			Id:       utils.MustInterface2Int64(mapData["id"]),
			ParentId: utils.MustInterface2Int64(mapData["pid"]),
			Name:     utils.Interface2String(mapData["shopCategoryName"]),
			Level:    int(utils.Interface2Int64WithDefault(mapData["shopCategoryLevel"], 0)),
			Sort:     int(utils.MustInterface2Int64(mapData["sort"])),
		}
	}
	return cat
}

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

// func getSkuAttr(weight float32) (attr string) {
// 	attr = fmt.Sprintf("约%dg", int(math.Round(float64(weight*1000))))
// 	return attr
// }
func genAttrMapList(kgAttr string) (attrList []map[string]interface{}) {
	return []map[string]interface{}{
		map[string]interface{}{
			"saleAttrName":      "规格",
			"saleAttrValueName": kgAttr,
		},
	}
}

func GetJdSkuIDFromError(err error) int64 {
	if err2, ok := err.(*utils.ErrorWithCode); ok && err2.IntCode() == 11001 && strings.Index(err2.ErrMsg(), "商家skuId已存在") >= 0 {
		searchResult := skuExistReg.FindStringSubmatch(err2.ErrMsg())
		if searchResult != nil && len(searchResult[1]) > 0 {
			return utils.Str2Int64(searchResult[1])
		}
	}
	return 0
}

// GetSkuCategoryBySkuName 根据商品名称获取商品分类
func (a *API) GetSkuCategoryBySkuName(productName string) (*GetSkuCategoryBySkuName, error) {
	result, err := a.AccessAPINoPage("pms/getSkuCateBrandBySkuName", map[string]interface{}{
		"productName": productName,
		"fields":      []string{"category", "brand"},
	}, nil, nil, nil)
	if err != nil {
		return nil, err
	}

	var recommendSku *GetSkuCategoryBySkuName
	if err := utils.Map2StructByJson(result, &recommendSku, false); err != nil {
		return nil, err
	}
	return recommendSku, nil
}

type GetSkuCategoryBySkuName struct {
	ProductName string `json:"productName"`
	CategoryId  int    `json:"categoryId"`
	BrandId     int    `json:"brandId"`
}
