package tiktok_store

import (
	"encoding/json"
	"errors"
	"fmt"
	product_addV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_addV2/response"
	beego "github.com/astaxie/beego/server/web"
	"strings"
	"time"
	"unicode"

	"git.rosy.net.cn/baseapi/platformapi/jdapi"
	"git.rosy.net.cn/baseapi/platformapi/mtwmapi"
	freightTemplate_create_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/freightTemplate_create/request"
	product_addV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_addV2/request"
	product_detail_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_detail/response"
	product_editV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_editV2/request"
	product_getCatePropertyV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_getCatePropertyV2/response"
	product_listV2_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/request"
	product_listV2_response "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/product_listV2/response"
	shop_bindStoreFreight_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/shop_bindStoreFreight/request"
	shop_bindStoreSaleLimit_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/shop_bindStoreSaleLimit/request"
	sku_editPrice_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_editPrice/request"
	sku_syncStock_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/sku_syncStock/request"
	trade_createTradeLimitTemplate_request "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/sdk-golang/api/trade_createTradeLimitTemplate/request"
	tiktokShop "git.rosy.net.cn/baseapi/platformapi/tiktok_shop/tiktok_api"
	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"git.rosy.net.cn/jx-callback/business/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"git.rosy.net.cn/jx-callback/business/partner"
	"git.rosy.net.cn/jx-callback/business/partner/putils"
	"git.rosy.net.cn/jx-callback/globals/api/apimanager"
)

type MainSku struct {
	AppOrgCode  string `json:"appOrgCode"`  // 账号id
	CheckStatus int64  `json:"checkStatus"` // 7-审核通过待上架 3-审核通过；
	StartTime   int64  `json:"startTime"`   // 商品创建开始时间，unix时间戳，单位：秒；
	EndTime     int64  `json:"endTime"`     // 商品创建结束时间，unix时间戳，单位：秒；
	Page        int64  `json:"page"`
	PageSize    int64  `json:"pageSize"`
}

type TiktokIdAndLocalSkuId struct {
	MainId     string `json:"mainId"`     // 商城商品主id
	LocalSkuId int64  `json:"localSkuId"` // 本地商品id
	SkuAttrId  string `json:"skuAttrId"`  // 主商品属性id
}

// QueryAllMainSkuList 获取商户账号总的商品,主商品条数.
func QueryAllMainSkuList(appOrgCode string, param *MainSku) ([]*TiktokIdAndLocalSkuId, error) {
	var (
		page                  int64 = 1
		pageSize              int64 = 100
		tiktokIdAndLocalSkuId       = make([]*TiktokIdAndLocalSkuId, 0, 0)
		api                         = getAPI(appOrgCode, 0, "")
	)
	if param.Page == 0 {
		param.Page = page
	}
	if param.PageSize == 0 {
		param.PageSize = pageSize
	}

	for {
		mainSkuList, err := GetSkuDetailList(api, param)
		if err != nil {
			return nil, err
		}
		for _, v := range mainSkuList.Data {
			var localSkuId int64 = 0
			skuDetail, err := api.GetSkuDetail(utils.Int64ToStr(v.ProductId), "")
			if err != nil {
				localSkuId = 0
			}
			if skuDetail.OutProductId != 0 {
				localSkuId = skuDetail.OutProductId
			} else if skuDetail.OuterProductId != "" {
				localSkuId = utils.Str2Int64(skuDetail.OuterProductId)
			} else {
				localSkuId = utils.Str2Int64(skuDetail.SpecPrices[0].Code)
			}

			var attrId []string
			for _, v := range skuDetail.SpecPrices {
				attrId = append(attrId, utils.Int64ToStr(v.SkuId))
			}

			tiktokIdAndLocalSkuId = append(tiktokIdAndLocalSkuId, &TiktokIdAndLocalSkuId{
				MainId:     skuDetail.ProductIdStr,
				LocalSkuId: localSkuId,
				SkuAttrId:  strings.Join(attrId, ","),
			})
		}

		if int64(len(mainSkuList.Data)) < pageSize {
			return tiktokIdAndLocalSkuId, err
		}
		param.Page++
	}

}

func GetSkuDetailList(api *tiktokShop.API, param *MainSku) (*product_listV2_response.ProductListV2Data, error) {
	mainSkuList, err := api.GetSkuDetailList(&product_listV2_request.ProductListV2Param{
		Status:          0,
		CheckStatus:     param.CheckStatus,
		ProductType:     0,
		StartTime:       param.StartTime,
		EndTime:         param.EndTime,
		Page:            param.Page,
		Size:            param.PageSize,
		UpdateStartTime: 0,
		UpdateEndTime:   0,
		StoreId:         0,
	})
	if err != nil {
		return nil, err
	}
	return mainSkuList, nil
}

// 对于多门店平台来说，storeSkuList中只有SkuID与VendorSkuID有意义
// 抖店的商品只管创建,创建接口会返回成功,但是审核的时候不一定成功.当前系统无法判定此商品是否已经创建过了!
func (p *PurchaseHandler) createOrUpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo, isCreate bool) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	var syncType string
	db := dao.GetDB()
	storeDetail, _ := dao.GetStoreDetail(db, storeID, model.VendorIDDD, "")
	api := getAPI(storeDetail.VendorOrgCode, storeID, vendorStoreID)
	if isCreate {
		syncType = "创建商品"
		for _, storeSku := range storeSkuList { // 创建商品
			// 如果当前商品,主商品id,子商品id都已经存在了,就不在创建了,主要防止,后期更新时,某些商品为创建成功,批量修改数据库再去批量创建报错(商品已创建)
			if storeSku.VendorMainId != "" && storeSku.VendorSkuID != "" && len(storeSku.VendorSkuID) == 19 {
				continue
			}
			if storeSku.StoreSkuStatus != model.YES { // 未可售的商品不参与修改
				continue
			}
			// 根据本地商品id获取线上商品是否存在,存在则只创建子商品
			// 获取本地存储映射关系,获取本地主商品id是否存在
			localThing, _ := dao.GetThingToTiktokMapList(db, model.VendorIDDD, int64(storeSku.SkuID), storeDetail.VendorOrgCode)
			if len(localThing) == 0 {
				param, failedList2 := makeMainProductSku(db, api, storeSku, storeDetail, storeID, vendorStoreID, syncType)
				if len(failedList2) != 0 {
					storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
					failedList = append(failedList, failedList2...)
					continue
				}
				tiktokResult, errCreate := api.CreateStoreCommodity(param) // 创建主商品,同步主商品
				if tiktokResult == nil {
					tiktokResult = &product_addV2_response.ProductAddV2Data{}
				}
				if errCreate != nil {
					if strings.Contains(errCreate.Error(), "outProductId或者outerProductId已经存在") { // 主品以创建但是未返回出来
						mainProductDetail, _ := api.GetSkuDetail("", utils.Int2Str(storeSku.SkuID))
						if mainProductDetail != nil || mainProductDetail.ProductId != 0 {
							tiktokResult.ProductId = mainProductDetail.ProductId
							specPrices := make([]product_addV2_response.SkuItem, 0, 0)
							for _, v := range mainProductDetail.SpecPrices {
								specPrices = append(specPrices, product_addV2_response.SkuItem{
									SkuId:         v.SkuId,
									OutSkuId:      v.OutSkuId,
									OuterSkuId:    v.OuterSkuId,
									Code:          v.Code,
									SpecDetailId1: v.SpecDetailId1,
									SpecDetailId2: v.SpecDetailId2,
									SpecDetailId3: v.SpecDetailId3,
								})
							}
							tiktokResult.Sku = specPrices
						} else {
							storeSku.SkuSyncStatus = 2 // 后续不在做定时任务更新
							storeSku.VendorSonSkuID = "此商品已经创建抖音主商品了"
							failedList = putils.GetErrMsg2FailedSingleList(storeSku, errCreate, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
							continue
						}
					} else if strings.Contains(errCreate.Error(), "无资质授权") {
						storeSku.SkuSyncStatus = 0 // 门店无资质不在做定时任务更新
						storeSku.VendorSonSkuID = "无资质授权"
						failedList = putils.GetErrMsg2FailedSingleList(storeSku, errCreate, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
						continue
					} else {
						storeSku.SkuSyncStatus = 2 // 门店无资质不在做定时任务更新
						storeSku.VendorSonSkuID = errCreate.Error()
						failedList = putils.GetErrMsg2FailedSingleList(storeSku, errCreate, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
						continue
					}
				}

				if tiktokResult.ProductId > model.NO {
					dao.CreateThingMap(int64(storeSku.SkuID), utils.Int64ToStr(tiktokResult.ProductId), storeDetail.VendorOrgCode, "创建成功", model.ThingTypeSku, model.ThingTypeSyncSuccess)
				}

				var attrId []string
				for _, v := range tiktokResult.Sku {
					attrId = append(attrId, utils.Int64ToStr(v.SkuId))
				}

				storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
				storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
				storeSku.VendorMainId = utils.Int64ToStr(tiktokResult.ProductId)
				storeSku.VendorSkuAttrId = strings.Join(attrId, ",")    // 属性id skuID
				storeSku.VendorSonSkuID = utils.Int2Str(storeSku.SkuID) // 还没同步子商品
				failedList = putils.GetErrMsg2FailedSingleList(storeSku, errors.New("只创建了主商品,没创建子商品"), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
			} else {
				switch localThing[0].SyncStatus {
				case model.ThingTypeSyncFail: // 同步失败在重新创建
					param, failedList2 := makeMainProductSku(db, api, storeSku, storeDetail, storeID, vendorStoreID, syncType)
					if len(failedList2) != 0 {
						failedList = append(failedList, failedList2...)
						continue
					}
					tiktokResult, err := api.CreateStoreCommodity(param) // 创建主商品,同步主商品
					if err != nil {
						storeSku.SkuSyncStatus = 0 // 只创建主品,子品都没做
						storeSku.VendorSonSkuID = err.Error()
						dao.UpdateThingMap(db, model.ThingTypeSyncingStop, err.Error(), storeSku.SkuID, model.VendorIDDD, storeDetail.VendorOrgCode)
						failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
						continue
					}

					if err := dao.UpdateThingMap(db, model.ThingTypeSyncSuccess, utils.Int64ToStr(tiktokResult.ProductId), storeSku.SkuID, model.VendorIDDD, storeDetail.VendorOrgCode); err != nil {
						storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
						failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
						continue
					}
					var attrId []string
					for _, v := range tiktokResult.Sku {
						attrId = append(attrId, utils.Int64ToStr(v.SkuId))
					}
					storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
					storeSku.VendorMainId = utils.Int64ToStr(tiktokResult.ProductId)
					storeSku.VendorSkuAttrId = strings.Join(attrId, ",") // 属性id skuID
					failedList = putils.GetErrMsg2FailedSingleList(storeSku, errors.New("只创建了主商品,没创建子商品"), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
				case model.ThingTypeSyncing:
					if time.Now().Unix()-localThing[0].CreatedAt.Unix() > 300 {
						dao.DeleteThingToTiktokMapList(model.VendorIDDD, localThing[0].VendorThingID, storeSku.SkuID)
					}
					storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
					failedList = putils.GetErrMsg2FailedSingleList(storeSku, errors.New("商品同步中或同步错误"), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					continue
				case model.ThingTypeSyncSuccess:
					// 主商品存在,直接同步子商品
					childrenProductId, sonSkuId, err := api.CreateSubProduct(utils.Str2Int64(localThing[0].VendorThingID), utils.Str2Int64(vendorStoreID))
					//if err != nil && strings.Contains(err.Error(), "2010004") { // 2010004:主商品非在线审核通过状态，不允许绑定子商品
					//	// 线上本地都存在,但是线上审核不成功,就去更新主商品
					//	mainOrderDetail = loadMainProductId(api, storeSku, localThing[0].VendorThingID)
					//	if mainOrderDetail.CheckStatus == tiktokShop.SkuCheckStatusProhibit || mainOrderDetail.CheckStatus == tiktokShop.SkuCheckStatusNotPass {
					//		// 更新主商品,在同步到子门店,考虑审核时间
					//		param, failedList2 := makeMainProductSku(db, api, storeSku, storeDetail, storeID, vendorStoreID, syncType)
					//		if len(failedList2) != 0 {
					//			failedList = append(failedList, failedList2...)
					//			continue
					//		}
					//		updateParam := &product_editV2_request.ProductEditV2Param{
					//			PayType:          tiktokShop.TiktokPayType1,
					//			ReduceType:       tiktokShop.SkuReduceTypePayMakeOrder,
					//			Weight:           utils.Int2Float64(storeSku.Weight),
					//			DeliveryDelayDay: tiktokShop.DeliveryDelayDayToDay,
					//			PresellType:      tiktokShop.SendGoodsTypeNow,
					//			Mobile:           storeDetail.Tel1,
					//			Commit:           true,
					//			Specs:            "重量|" + utils.Float64ToStr(float64(storeSku.SpecQuality)) + storeSku.SpecUnit,
					//			NeedRechargeMode: false,
					//			SellChannel:      []int64{0},
					//			StartSaleType:    0,
					//			PickupMethod:     "0",
					//			CategoryLeafId:   param.CategoryLeafId,
					//			Name:             param.Name,
					//			ProductFormatNew: param.ProductFormatNew,
					//		}
					//		// 是否支持七天无理由
					//		isAfterSale, rule := api.GetProductUpdateRule(param.CategoryLeafId)
					//		if isAfterSale {
					//			param.AfterSaleService = map[string]string{"supply_day_return_selector": fmt.Sprintf("%s", rule)}
					//		}
					//		updateParam.Pic = param.Pic
					//		updateParam.Description = param.Description
					//		updateParam.WeightUnit = tiktokShop.WeightUint_G
					//
					//		updateParam.ProductId = mainOrderDetail.ProductId
					//		updateParam.MainProductId = mainProductId
					//		updateParam.SpecPrices = param.SpecPrices
					//		updateParam.StandardBrandId = param.StandardBrandId
					//		if err2 := api.EditStoreCommodity(updateParam); err2 != nil {
					//			failedList = putils.GetErrMsg2FailedSingleList(storeSku, err2, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					//			storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
					//		}
					//		storeSku.SkuSyncStatus = model.SyncFlagNewMask // 只创建主品,子品都没做
					//		failedList = putils.GetErrMsg2FailedSingleList(storeSku, errors.New("修改主品,主品审核中/失败,子商品未创建"), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					//		continue
					//	}
					//}
					if sonSkuId != "" {
						storeSku.VendorSonSkuID = sonSkuId
					}

					if err != nil && strings.Contains(err.Error(), "2010001") { // 2010001:重复创建渠道商品
						storeSkuDetail, err := api.GetSkuDetailLocalID(vendorStoreID, utils.Int2Str(storeSku.SkuID))
						if err != nil {
							failedList3 := putils.GetErrMsg2FailedSingleList(storeSku, errors.New("获取子品详情错误:"+err.Error()), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
							failedList = append(failedList, failedList3...)
							continue
						}
						storeSku.VendorSkuID = utils.Int64ToStr(storeSkuDetail.ProductId)
						storeSku.VendorSonSkuID = utils.Int64ToStr(storeSkuDetail.SpecPrices[0].SkuId)
						childrenProductId = storeSkuDetail.ProductId
						dao.ExecuteSQL(dao.GetDB(), ` UPDATE store_sku_bind s SET s.dd_id = ?,s.vendor_son_sku_id = ? WHERE s.store_id = ? AND s.sku_id = ?`, []interface{}{storeSku.VendorSkuID, storeSku.VendorSonSkuID, storeID, storeSku.SkuID}...)
					}

					if childrenProductId != model.NO {
						// 同步价格,库存,上架
						skuId, failedList2 := upDateChildrenPriceStockLaunch(api, storeSku, childrenProductId, vendorStoreID, syncType)
						failedList = append(failedList, failedList2...)
						storeSku.VendorSonSkuID = utils.Int64ToStr(skuId)          // (属性id skuID方案一)(自商品的商品id方案二)
						storeSku.VendorSkuID = utils.Int64ToStr(childrenProductId) // 子商品主id
						storeSku.VendorMainId = localThing[0].VendorThingID        // 商品主id
					}

					if err != nil {
						failedList4 := putils.GetErrMsg2FailedSingleList(storeSku, errors.New("创建子品异常:"+err.Error()), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
						failedList = append(failedList, failedList4...)
						continue
					}
				}
			}
		}
	} else {
		syncType = "更新商品"
		for _, storeSku := range storeSkuList {
			if storeSku.StoreSkuStatus != model.YES { // 未可售的商品不参与修改
				continue
			}

			// 更新主商品,在同步到子门店,考虑审核时间
			param := &product_editV2_request.ProductEditV2Param{
				Name:             utils.String2Pointer(utils.LimitUTF8StringLen(storeSku.SkuName, 90)),
				PayType:          utils.Int64ToPointer(tiktokShop.TiktokPayType1),
				ReduceType:       utils.Int64ToPointer(tiktokShop.SkuReduceTypePayMakeOrder),
				Weight:           utils.Float64ToPointer(utils.Int2Float64(storeSku.Weight)),
				DeliveryDelayDay: utils.Int64ToPointer(tiktokShop.DeliveryDelayDayToDay),
				PresellType:      utils.Int64ToPointer(tiktokShop.SendGoodsTypeNow),
				Mobile:           utils.String2Pointer(storeDetail.Tel1),
				Commit:           true,
				Specs:            utils.String2Pointer("总净重|" + utils.Float64ToStr(float64(storeSku.SpecQuality)) + storeSku.SpecUnit),
				NeedRechargeMode: nil,
				SellChannel:      []int64{0},
				StartSaleType:    utils.Int64ToPointer(0),
				PickupMethod:     utils.String2Pointer("0"),
			}
			param.Name = utils.String2Pointer(checkNameLength(*param.Name))

			// 暂时只考虑修改白底图,提高效率.其余图片不做修改
			img, descImg, whiteImg, err := GetTiktokImgList(api, utils.Int2Str(storeSku.StoreID), storeSku.SkuID, storeSku.DescImg, storeSku.Img, []string{storeSku.Img2, storeSku.Img3, storeSku.Img4, storeSku.Img5})
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
				continue
			}
			param.Pic = utils.String2Pointer(img)
			param.Description = utils.String2Pointer(descImg)
			param.WhiteBackGroundPicUrl = utils.String2Pointer(whiteImg)
			param.WeightUnit = utils.Int64ToPointer(tiktokShop.WeightUint_G)

			// 部分商品没有所属的分类,直接跳过!
			// 老的类目长度小于十
			var vendorCategoryId int64 = 0
			var isUpdate bool = false
			if storeSku.SkuVendorMapCatID == "" {
				if vendorCategoryId, _ = api.GetRecommendCategory(strings.Split(img, "|")); vendorCategoryId == 0 { // 根据图片推导分类
					vendorCategoryId, _ = api.GetRecommendCategoryByName(storeSku.SkuName) // 根据名字推导分类
				}
				isUpdate = true
			} else if len(storeSku.SkuVendorMapCatID) < 10 {
				// 用老的分类ID换取新的分类ID
				newCategoryMap, err := api.BatchGetChannelCategoryMapping([]int64{utils.Str2Int64(storeSku.SkuVendorMapCatID)})
				if err != nil {
					failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					continue
				}
				vendorCategoryId = newCategoryMap[storeSku.VendorVendorCatID]
				isUpdate = true
			} else {
				vendorCategoryId = utils.Str2Int64(storeSku.SkuVendorMapCatID)
			}
			if isUpdate {
				dao.ExecuteSQL(db, `UPDATE sku_vendor_category_map SET vendor_category_id = ? WHERE name_id = ? AND vendor_id = ? `, []interface{}{utils.Int64ToStr(vendorCategoryId), storeSku.NameID, model.VendorIDDD})
			}
			param.CategoryLeafId = utils.Int64ToPointer(vendorCategoryId)

			isAfterSale, rule := api.GetProductUpdateRule(*param.CategoryLeafId)
			if isAfterSale {
				param.AfterSaleService = &map[string]string{"supply_day_return_selector": fmt.Sprintf("%s", rule)}
			}
			// 获取主商品id
			var mainIdInt int64
			if storeSku.VendorMainId == "" {
				localThing, _ := dao.GetThingToTiktokMapList(db, model.VendorIDDD, int64(storeSku.SkuID), storeDetail.VendorOrgCode)
				if len(localThing) == 0 || localThing == nil {
					failedList = putils.GetErrMsg2FailedSingleList(storeSku, errors.New(fmt.Sprintf("更新主品失败,请创建主品skuId[storeId:%d,skuId:%d]", storeID, storeSku.SkuID)), storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					continue
				} else {
					storeSku.VendorMainId = localThing[0].VendorThingID
					mainIdInt = utils.Str2Int64(localThing[0].VendorThingID)
				}
			} else {
				mainIdInt = utils.Str2Int64(storeSku.VendorMainId)
			}

			// 更新商品,主品如果名字和类目没变化,则更新子品价格!
			//mainProductDetail, err := api.GetSkuDetail(utils.Int64ToStr(mainIdInt), "")
			//if err != nil || mainProductDetail == nil {
			//	failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
			//	continue
			//}
			//if mainProductDetail.Name == param.Name && (mainProductDetail.CategoryDetail.ThirdCid == param.CategoryLeafId || mainProductDetail.CategoryDetail.FourthCid == param.CategoryLeafId) {
			//	// 更新子品,同步方法会更新子品的同时去更新库存和价格!删除之后接下的同步步骤失效!
			//	failedList2 := upDateChildrenPriceStockLaunch(api, storeSku, utils.Str2Int64(storeSku.VendorSkuID), vendorStoreID, syncType)
			//	failedList = append(failedList, failedList2...)
			//	continue
			//}

			// 获取商品的属性
			if storeSku.TiktokAttribute != "" && storeSku.TiktokAttribute != "{}" && storeSku.UpcTiktokBrandId != "" {
				param.ProductFormatNew = utils.String2Pointer(storeSku.TiktokAttribute)
			} else {
				productFormatNew, standardBrandId, err := MakeProductFormatNew(api, int64(storeSku.NameID), *param.CategoryLeafId, storeSku.Upc, storeSku.UpcBrandName, storeSku.UpcTiktokBrandId)
				if err != nil {
					failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
					continue
				}
				param.ProductFormatNew = utils.String2Pointer(productFormatNew)
				param.StandardBrandId = utils.Int64ToPointer(standardBrandId)
			}

			// 获取品牌
			if param.StandardBrandId == utils.Int64ToPointer(model.NO) {
				standardBrandId, _ := getTiktokBrandId(api, db, storeSku.Upc, storeSku.UpcBrandName, storeSku.UpcTiktokBrandId, *param.CategoryLeafId)
				if standardBrandId != 0 {
					param.StandardBrandId = utils.Int64ToPointer(standardBrandId)
				} else {
					param.StandardBrandId = utils.Int64ToPointer(596120136)
				}
			}

			// 修改商品
			param.ProductId = mainIdInt
			param.SpecPrices = utils.String2Pointer(GetSpecPrices(*param.Specs, vendorStoreID, mainIdInt, storeSku))
			err = api.EditStoreCommodity(param)
			if err != nil && !strings.Contains(err.Error(), "您上传的商品主图存在重复") {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
				//storeSku.VendorSkuID = utils.Int2Str(storeSku.SkuID)
			} else {
				skuId, _ := upDateChildrenPriceStockLaunch(api, storeSku, utils.Str2Int64(storeSku.VendorSkuID), vendorStoreID, syncType)
				storeSku.VendorSonSkuID = utils.Int64ToStr(skuId) // 品库修改 售卖状态待同步 价格待同步
			}
			//storeSku.SkuSyncStatus = model.SyncFlagStoreSkuModifiedMask // 品库修改 售卖状态待同步 价格待同步
			storeSku.SkuSyncStatus = 0 // 品库修改 售卖状态待同步 价格待同步
		}
		return
	}
	return failedList, err
}

func makeMainProductSku(db *dao.DaoDB, api *tiktokShop.API, storeSku *dao.StoreSkuSyncInfo, storeDetail *dao.StoreDetail, storeID int, vendorStoreID, syncType string) (param *product_addV2_request.ProductAddV2Param, failedList []*partner.StoreSkuInfoWithErr) {
	param = &product_addV2_request.ProductAddV2Param{
		Name:             utils.LimitUTF8StringLen(storeSku.SkuName, 90),
		PayType:          utils.Int64ToPointer(tiktokShop.TiktokPayType1),
		ReduceType:       tiktokShop.SkuReduceTypePayMakeOrder,
		Weight:           utils.Float64ToPointer(utils.Int2Float64(storeSku.Weight)),
		DeliveryDelayDay: utils.Int64ToPointer(tiktokShop.DeliveryDelayDayToDay),
		PresellType:      utils.Int64ToPointer(tiktokShop.SendGoodsTypeNow),
		Mobile:           storeDetail.Tel1,
		Commit:           true,
		Specs:            utils.String2Pointer("总净重|" + utils.Float64ToStr(float64(storeSku.SpecQuality)) + storeSku.SpecUnit),
		NeedRechargeMode: nil,
		SellChannel:      []int64{0},
		StartSaleType:    utils.Int64ToPointer(0),
		PickupMethod:     utils.String2Pointer("0"),
		OuterProductId:   utils.String2Pointer(utils.Int2Str(storeSku.SkuID)), // 本地skuId为外部商品id
		ProductType:      0,
	}
	param.Name = checkNameLength(param.Name)

	// 获取上传图,商品轮播图
	img, detailImg, whiteImg, err := GetTiktokImgList(api, utils.Int2Str(storeSku.StoreID), storeSku.SkuID, storeSku.DescImg, storeSku.Img, []string{storeSku.Img2, storeSku.Img3, storeSku.Img4, storeSku.Img5})
	if err != nil {
		failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
		return
	}
	param.Pic = img
	param.Description = detailImg
	param.WhiteBackGroundPicUrl = utils.String2Pointer(whiteImg)

	// 老的类目长度小于十
	var vendorCategoryId int64 = 0
	var isUpdate bool = false
	if storeSku.SkuVendorMapCatID == "" {
		if vendorCategoryId, _ = api.GetRecommendCategory(strings.Split(img, "|")); vendorCategoryId == 0 { // 根据图片推导分类
			vendorCategoryId, _ = api.GetRecommendCategoryByName(storeSku.SkuName) // 根据名字推导分类
		}
		isUpdate = true
	} else if len(storeSku.SkuVendorMapCatID) < 10 {
		// 用老的分类ID换取新的分类ID
		newCategoryMap, err := api.BatchGetChannelCategoryMapping([]int64{utils.Str2Int64(storeSku.SkuVendorMapCatID)})
		if err != nil {
			return nil, putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
		}
		vendorCategoryId = newCategoryMap[storeSku.VendorVendorCatID]
		isUpdate = true
	} else {
		vendorCategoryId = utils.Str2Int64(storeSku.SkuVendorMapCatID)
	}
	if isUpdate {
		dao.ExecuteSQL(db, `UPDATE sku_vendor_category_map SET vendor_category_id = ? WHERE name_id = ? AND vendor_id = ? `, []interface{}{utils.Int64ToStr(vendorCategoryId), storeSku.NameID, model.VendorIDDD})
	}
	param.CategoryLeafId = vendorCategoryId

	// 这个情况是原有商品不存在和推荐查询不到类目id是,使用京西类目和抖音类目的绑定关系
	// 但是不太实用,导致商品类目错误被暂停营业等
	//if storeSku.VendorVendorCatID != 0 && param.CategoryLeafId == 0 {
	//	param.CategoryLeafId = storeSku.VendorVendorCatID
	//}

	isAfterSale, rule := api.GetProductUpdateRule(param.CategoryLeafId)
	if isAfterSale {
		param.AfterSaleService = &map[string]string{"supply_day_return_selector": fmt.Sprintf("%s", rule)}
	}

	// weight_unit 目前抖音只支持g和kg两种
	param.WeightUnit = utils.Int64ToPointer(tiktokShop.WeightUint_G)

	// spec_prices
	param.SpecPrices = utils.String2Pointer(GetSpecPrices(*param.Specs, vendorStoreID, 0, storeSku))
	// 获取商品的属性
	if storeSku.TiktokAttribute != "" && storeSku.TiktokAttribute != "{}" && storeSku.UpcTiktokBrandId != "" {
		param.ProductFormatNew = utils.String2Pointer(storeSku.TiktokAttribute)
	} else {
		productFormatNew, standardBrandId, err := MakeProductFormatNew(api, int64(storeSku.NameID), param.CategoryLeafId, storeSku.Upc, storeSku.UpcBrandName, storeSku.UpcTiktokBrandId)
		if err != nil {
			failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
			return
		}
		param.ProductFormatNew = utils.String2Pointer(productFormatNew)
		param.StandardBrandId = utils.Int64ToPointer(standardBrandId)
	}

	if param.StandardBrandId == utils.Int64ToPointer(model.NO) {
		standardBrandId, _ := getTiktokBrandId(api, db, storeSku.Upc, storeSku.UpcBrandName, storeSku.UpcTiktokBrandId, param.CategoryLeafId)
		if standardBrandId != 0 {
			param.StandardBrandId = utils.Int64ToPointer(standardBrandId)
		} else {
			param.StandardBrandId = utils.Int64ToPointer(596120136)
		}
	}

	freightId, saleLimitId, err := getFreightIdAndSaleLimitId(api, db, storeDetail, vendorStoreID)
	if err != nil {
		failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeID, model.VendorChineseNames[model.VendorIDDD], syncType)
		return
	}
	param.FreightId = freightId
	param.SaleLimitId = utils.Int64ToPointer(saleLimitId)
	return
}

func getTiktokBrandId(api *tiktokShop.API, db *dao.DaoDB, upc, upcBrandName, upcTiktokBrandId string, categoryLeafId int64) (int64, error) {
	if upc == "" { // 默认品牌京西菜市 596120136
		return 596120136, nil
	} else if upc != "" && upcBrandName != "" && upcTiktokBrandId != "" {
		return utils.Str2Int64(upcTiktokBrandId), nil
	} else if upc != "" && upcBrandName != "" && upcTiktokBrandId == "" {
		brandName := upcBrandName
		if strings.Contains(brandName, "/") {
			brandName = strings.Split(brandName, "/")[0]
		}
		if strings.Contains(brandName, "(") {
			brandName = strings.Split(brandName, "(")[0]
		}
		if strings.Contains(brandName, "（") {
			brandName = strings.Split(brandName, "（")[0]
		}
		standardBrandId, err := api.GetSkuBrand(categoryLeafId, brandName)
		if err != nil {
			return 0, err
		}
		dao.UpdateSkuNameTiktokBrandName(db, upc, upcBrandName, utils.Int64ToStr(standardBrandId))
		return standardBrandId, nil
	} else if upc != "" && upcBrandName == "" && upcTiktokBrandId == "" {
		brandName, err := GetBrandByBrandName(upc)
		if err != nil {
			return 0, err
		}
		if strings.Contains(brandName, "/") || strings.Contains(brandName, "(") || strings.Contains(brandName, "（") {
			brandName = strings.Split(brandName, "/")[0]
		}
		if strings.Contains(brandName, "(") {
			brandName = strings.Split(brandName, "(")[0]
		}
		if strings.Contains(brandName, "（") {
			brandName = strings.Split(brandName, "（")[0]
		}
		standardBrandId, err := api.GetSkuBrand(categoryLeafId, brandName)
		if err != nil {
			return 0, err
		}
		dao.UpdateSkuNameTiktokBrandName(db, upc, brandName, utils.Int64ToStr(standardBrandId))
		return standardBrandId, nil
	}
	return 0, errors.New("getTiktokBrandId 获取抖音品牌id异常")
}

func GetBrandByBrandName(upcCode string) (string, error) {
	vendorOrgCode := ""
	if beego.BConfig.RunMode == model.ServerTypeFruits {
		vendorOrgCode = jdapi.JdVendorOrgCodeFruit
	} else if beego.BConfig.RunMode == model.ServerTypePet {
		vendorOrgCode = jdapi.JdVendorOrgCodePet
	} else {
		vendorOrgCode = jdapi.JdVendorOrgCodeVagetable
	}
	apijd := apimanager.CurAPIManager.GetAPI(model.VendorIDJD, vendorOrgCode).(*jdapi.API)
	result, err := apijd.GetJdUpcCodeByName("", upcCode, 1, 5)
	if err != nil {
		return "", err
	}
	if len(result) != model.YES {
		return "", fmt.Errorf("upc码[%s],获取商品不唯一", upcCode)
	}

	if result[0].BrandName != "" {
		return result[0].BrandName, nil
	}
	return strings.Split(result[0].OriginalName, " ")[0], nil
}

func loadMainProductId(api *tiktokShop.API, storeSku *dao.StoreSkuSyncInfo, mainProductId string) *product_detail_response.ProductDetailData {
	// 这有可能获取的值主商品也有可能是子商品,我们需要的是主商品id和状态
	mainOrderDetailProductId, err := api.GetSkuDetail(mainProductId, "")
	if err != nil || mainOrderDetailProductId == nil {
		mainOrderDetailProductId.MainProductId = 0
		mainOrderDetailProductId.CheckStatus = 4
		return mainOrderDetailProductId
	}
	return mainOrderDetailProductId
}

func checkNameLength(name string) string {
	var chinesLen int // 中文
	var punctZh int   // 中文标点
	var punctEn int   // 英文标点
	var punctAZ int   // 字母
	var punctNum int  // 字母
	var spance int    // 空格
	for _, v := range name {
		if unicode.Is(unicode.Han, v) { // 中文
			chinesLen++
			continue
		}
		if unicode.IsPunct(v) {
			if v >= 1000 { // 中文字符
				fmt.Println(v)
				punctZh++
			} else {
				punctEn++ // 英文字符
			}
			continue
		}
		if unicode.IsLetter(v) { // 字母
			punctAZ++
			continue
		}
		if unicode.IsNumber(v) { // 数字
			punctNum++
			continue
		}
		if unicode.IsSpace(v) { // 空格
			spance++
			continue
		}
	}

	maxLen := (chinesLen * 2) + (punctZh * 2) + punctEn + punctAZ + punctNum + spance
	if maxLen > 60 { // 美团最多支持30个汉字长度
		index := strings.LastIndex(name, " ")
		if index != 0 {
			return name[0:index]
		} else {
			return name[0 : len(name)-(maxLen-60)*3]
		}
	} else if maxLen < 16 {
		name += "【同城配送】"
		return name
	}
	return name
}
func upDateChildrenPriceStockLaunch(api *tiktokShop.API, storeSku *dao.StoreSkuSyncInfo, childrenProductId int64, vendorStoreID, syncType string) (skuID int64, failedList []*partner.StoreSkuInfoWithErr) {
	skuId, failed := getProductSkuID(api, storeSku, syncType, childrenProductId)
	if skuId == 0 || len(failed) > 0 {
		return 0, failed
	}
	// 同步价格
	if err := api.EditPrice(&sku_editPrice_request.SkuEditPriceParam{
		SkuId:     skuId,
		Price:     storeSku.VendorPrice,
		ProductId: childrenProductId,
	}); err != nil {
		failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeSku.StoreID, model.VendorChineseNames[model.VendorIDDD], syncType)
	}

	// 同步库存
	paramStock := &sku_syncStock_request.SkuSyncStockParam{
		ProductId:   childrenProductId,
		Incremental: false,
		StockNum:    int64(storeSku.Stock),
		OutSkuId:    int64(storeSku.SkuID),
	}
	if paramStock.StockNum == 0 && beego.BConfig.RunMode != model.ServerTypePet {
		paramStock.StockNum = 99999
	}
	if err := api.UpdateSkuStock(paramStock); err != nil {
		failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSku, err, storeSku.StoreID, model.VendorChineseNames[model.VendorIDDD], fmt.Sprintf("子商品添加固定库存.%s", err.Error()))...)
	}

	// 上架
	if err := api.LaunchProduct(childrenProductId); err != nil {
		failedList = append(failedList, putils.GetErrMsg2FailedSingleList(storeSku, err, storeSku.StoreID, model.VendorChineseNames[model.VendorIDDD], fmt.Sprintf("上架子商品异常.%s", err.Error()))...)
	}
	if len(failedList) > 0 {
		storeSku.SkuSyncStatus = model.SyncFlagStoreSkuModifiedMask
	} else {
		storeSku.SkuSyncStatus = 0
	}
	return skuId, failedList
}

// 查询商品详情,获取商品的抖音skuId
func getProductSkuID(api *tiktokShop.API, storeSku *dao.StoreSkuSyncInfo, syncType string, productId int64) (childrenSkuId int64, failedList []*partner.StoreSkuInfoWithErr) {
	if storeSku.VendorSonSkuID != "" && storeSku.VendorSonSkuID != storeSku.VendorSkuID && utils.Int2Str(storeSku.SkuID) != storeSku.VendorSkuID {
		return utils.Str2Int64(storeSku.VendorSonSkuID), nil
	}
	childrenDetail, err := api.GetSkuDetail(utils.Int64ToStr(productId), "")
	if err != nil {
		failedList = putils.GetErrMsg2FailedSingleList(storeSku, err, storeSku.StoreID, model.VendorChineseNames[model.VendorIDDD], syncType)
		return 0, failedList
	}

	for _, v := range childrenDetail.SpecPrices {
		childrenSkuId = v.SkuId
		storeSku.VendorSonSkuID = utils.Int64ToStr(childrenSkuId)
		return childrenSkuId, nil
	}
	return 0, putils.GetErrMsg2FailedSingleList(storeSku, fmt.Errorf("获取商品抖音skuId失败[%d]", productId), storeSku.StoreID, model.VendorChineseNames[model.VendorIDDD], syncType)
}

func getProductSkuId4UpdateStock(api *tiktokShop.API, skuInfo *partner.StoreSkuInfo, storeId int, vendorStoreId string) (tiktokSkuId int64, failedList []*partner.StoreSkuInfoWithErr) {
	if skuInfo.VendorSonSkuID != "" && skuInfo.VendorSonSkuID != skuInfo.VendorSkuID { // 抖音长度
		return utils.Str2Int64(skuInfo.VendorSonSkuID), nil
	}

	var childrenSku *product_detail_response.ProductDetailData
	var err error
	if len(skuInfo.VendorSkuID) >= len("3589393056912261100") {
		childrenSku, err = api.GetSkuDetail(skuInfo.VendorSkuID, "")
		if err != nil || len(childrenSku.SpecPrices) <= 0 {
			failedList = append(failedList, putils.GetErrMsg2FailedSingleList(skuInfo, err, storeId, model.VendorChineseNames[model.VendorIDDD], "修改库存[err为空,子商品skuId未获取到]")...)
			return 0, failedList
		}
	} else {
		childrenSku, err = api.GetSkuDetailLocalID(vendorStoreId, skuInfo.VendorSkuID)
		if err != nil || len(childrenSku.SpecPrices) <= 0 {
			failedList = append(failedList, putils.GetErrMsg2FailedSingleList(skuInfo, err, storeId, model.VendorChineseNames[model.VendorIDDD], "修改库存[err为空,子商品skuId未获取到]")...)
			return 0, failedList
		}
	}

	for _, v := range childrenSku.SpecPrices {
		tiktokSkuId = v.SkuId
		skuInfo.VendorSonSkuID = utils.Int64ToStr(v.SkuId)
		skuInfo.VendorSkuID = childrenSku.ProductIdStr
		dao.ExecuteSQL(dao.GetDB(), ` UPDATE store_sku_bind s SET s.dd_id = ?,s.vendor_son_sku_id = ? WHERE s.store_id = ? AND s.sku_id = ?`, []interface{}{skuInfo.VendorSkuID, skuInfo.VendorSonSkuID, storeId, skuInfo.SkuID}...)
		return tiktokSkuId, nil
	}

	return 0, append(failedList, putils.GetErrMsg2FailedSingleList(skuInfo, nil, storeId, model.VendorChineseNames[model.VendorIDDD], "修改库存,获取商品详情SkuId未获取到")...)
}

func getFreightIdAndSaleLimitId(api *tiktokShop.API, db *dao.DaoDB, storeDetail *dao.StoreDetail, vendorStoreID string) (freightId, saleLimitId int64, err error) {
	temp, err := dao.QueryStoreBindInfo(storeDetail.Store.ID)
	if err != nil || temp == nil || temp.ID == 0 {
		// 运费模板
		freightId, err = GetDeliveryTemp(api, vendorStoreID, storeDetail)
		if err != nil {
			return 0, 0, err
		}
		// 获取门店限售模板
		saleLimitId, err = CreateSaleTemp(utils.Str2Int64(vendorStoreID), api)
		if err != nil {
			return 0, 0, err
		}
		// 保存数据库
		freightTemplate := &model.FreightTemplate{
			StoreID:       storeDetail.Store.ID,
			VendorStoreID: storeDetail.VendorStoreID,
			TemplateID:    freightId,
			WarehouseID:   0,
			FenceID:       "",
			TradeLimitID:  saleLimitId,
		}
		err = dao.CreateEntity(db, freightTemplate)
	} else {
		if temp.TemplateID != 0 {
			freightId = temp.TemplateID
		} else {
			// 运费模板
			freightId, err = GetDeliveryTemp(api, vendorStoreID, storeDetail)
			if err != nil {
				return 0, 0, err
			}
			temp.TemplateID = freightId
			_, err = dao.UpdateEntity(db, temp, "TemplateID")
			dao.FreightTemplateMap[temp.StoreID] = temp
		}

		if temp.TradeLimitID != 0 {
			saleLimitId = temp.TradeLimitID
		} else {
			// 获取门店限售模板
			saleLimitId, err = CreateSaleTemp(utils.Str2Int64(vendorStoreID), api)
			if err != nil {
				return 0, 0, err
			}
			temp.TradeLimitID = saleLimitId
			_, err = dao.UpdateEntity(db, temp, "TradeLimitID")
			dao.FreightTemplateMap[temp.StoreID] = temp
		}
	}

	return freightId, saleLimitId, nil
}

// CreateSaleTemp 创建限售模板
func CreateSaleTemp(storeId int64, api *tiktokShop.API) (int64, error) {
	// 获取限售模板
	saleLimitId, _ := api.StoreQuerySaleLimitTemp(storeId)
	if saleLimitId != 0 {
		return saleLimitId, nil
	}

	// 创建限售模板
	param := &trade_createTradeLimitTemplate_request.TradeCreateTradeLimitTemplateParam{
		StoreId:                   storeId,
		TradeLimitRuleRequestList: []trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem{},
	}
	tradeLimitRuleRequestList := make([]trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem, 0)
	tradeLimitRuleRequest := trade_createTradeLimitTemplate_request.TradeLimitRuleRequestListItem{
		TradeLimitModel:    1, // 限购模型 1-重量，2-数量，3-地区，4-金额
		TradeLimitResource: 2, // 限购资源类别1-抖店，2-门店，3-商品ID，4-sku,5-类目，6-活动，7-商品标
		TradeLimitPattern: &trade_createTradeLimitTemplate_request.TradeLimitPattern{
			Minimum:       1,                 // 1毫克
			Maximum:       500 * 1000 * 1000, //500千克
			CumulativeMax: 99999,
		},
		TradeLimitSubjectList: []int32{1},
	}
	tradeLimitRuleRequestList = append(tradeLimitRuleRequestList, tradeLimitRuleRequest)
	result, err := api.CreateTradeLimitTemplate(param)
	if err != nil {
		return 0, err
	}

	if result.TradeLimitId == 0 {
		return 0, errors.New("限售模板创建错误,联系管理员")
	}

	// 绑定限售模板
	if err := api.BindStoreSaleLimit(&shop_bindStoreSaleLimit_request.ShopBindStoreSaleLimitParam{
		StoreId:     storeId,
		SaleLimitId: result.TradeLimitId,
	}); err != nil {
		return 0, err
	}

	return result.TradeLimitId, nil
}

// GetDeliveryTemp 获取运费模板id,运费模板不存在则创建
func GetDeliveryTemp(api *tiktokShop.API, vendorStoreID string, storeDetail *dao.StoreDetail) (int64, error) {
	if vendorStoreID == "" {
		return 0, errors.New("平台门店id未绑定")
	}
	// 没有模板是查询线上模板
	freightId, _ := api.GetStoreBindTemp(utils.Str2Int64(vendorStoreID))
	if freightId == 0 {
		// 创建门店运费模板
		productProvince := utils.Str2Int64(utils.Int2Str(storeDetail.ProvinceCode)[0:2])
		tempDetail := &freightTemplate_create_request.FreightTemplateCreateParam{
			Template: &freightTemplate_create_request.Template{
				TemplateName:    utils.Int2Str(storeDetail.ID) + "的",
				ProductProvince: productProvince,
				CalculateType:   2,
				TransferType:    1,   // 快递方式-1.快递 目前仅支持1
				RuleType:        1,   // 模板类型-0:阶梯计价 1:固定运费 2:卖家包邮 3:货到付款
				FixedAmount:     500, //固定运费 单位：分
			},
		}
		//直辖市特殊处理
		if flag, code := HandleMunicipality(storeDetail.CityName); flag {
			tempDetail.Template.ProductCity = code
		} else {
			tempDetail.Template.ProductCity = int64(storeDetail.CityCode)
		}
		if storeDetail.DeliveryFeeDeductionSill == 0 { // 固定运费模板
			tempDetail.Template.TemplateName += "固定运费模板"
		} else { // 满减运费模板
			tempDetail.Template.TemplateName += "满减运费模板"
			tempDetail.Columns = []freightTemplate_create_request.ColumnsItem{{
				IsOverFree: true, //是否包邮
				IsLimited:  false,
				OverAmount: int64(storeDetail.DeliveryFeeDeductionSill), //此字段在vendor_id=14时 存储满x包邮金额
			}}
		}
		temp, err := api.FreightTemplateCreate(tempDetail)
		if err != nil {
			return 0, err
		}

		// 绑定门店运费模板
		if err = api.BindFreightTemplate(&shop_bindStoreFreight_request.ShopBindStoreFreightParam{
			StoreId:   utils.Str2Int64(vendorStoreID),
			FreightId: temp.TemplateId,
		}); err != nil {
			return 0, err
		}
		freightId = temp.TemplateId
	}
	return freightId, nil
}

// GetProductFormatNew 获取物品属性
func GetProductFormatNew(categoryLeftId int64, vendorOrgCode string) (*product_getCatePropertyV2_response.ProductGetCatePropertyV2Response, error) {
	category, err := getAPI(vendorOrgCode, 0, "").GetCatePropertyV2(categoryLeftId)
	if err != nil {
		return nil, err
	}
	return category, nil
	//format := make(map[string][]*tiktokShop.ProductFormatNewList, 0)
	//for _, v := range category.Data.Data {
	//	if v.Required != 1 { // 必填属性必须填写
	//		continue
	//	}
	//	for _, d := range v.Options {
	//		formateNew := &tiktokShop.ProductFormatNewList{
	//			Value:   utils.Str2Int64(d.Value),
	//			Name:    d.Name,
	//			DiyType: v.DiyType,
	//		}
	//		format[utils.Int64ToStr(v.PropertyId)] = append(format[utils.Int64ToStr(v.CategoryId)], formateNew)
	//	}
	//}
	//productFormatNew, err := json.Marshal(format)
	//if err != nil {
	//	return "", err
	//}
	//return string(productFormatNew), nil
}

type VendorCategoryId struct {
	VendorCategoryID string `orm:"column(vendor_category_id)" json:"vendorCategoryID"`
}

func BatchGetChannelCategoryMapping() error {
	var db = dao.GetDB()
	sql := ` SELECT vendor_category_id FROM sku_vendor_category_map WHERE vendor_id = 14 GROUP BY vendor_category_id`
	data := make([]*VendorCategoryId, 0, 0)
	if err := dao.GetRows(db, &data, sql, nil); err != nil {
		return err
	}
	if len(data) == 0 {
		return fmt.Errorf("未查询到数据")
	}
	count := len(data) / 50
	if len(data)%50 != 0 {
		count = count + 1
	}

	categoryList := make([]int64, 0, len(data))
	for _, v := range data {
		if len(v.VendorCategoryID) < 10 {
			categoryList = append(categoryList, utils.Str2Int64(v.VendorCategoryID))
		}
	}
	api := getAPI("260477060", 0, "")
	for i := 1; i <= count; i++ {
		cats := make(map[int64]int64, 50)
		if i == count {
			cats, _ = api.BatchGetChannelCategoryMapping(categoryList[(i-1)*50:])
		} else {
			cats, _ = api.BatchGetChannelCategoryMapping(categoryList[(i-1)*50 : i*50])
		}

		for k, c := range cats {
			sql2 := ` UPDATE sku_vendor_category_map SET vendor_category_id = ? WHERE vendor_category_id = ?`
			param := []interface{}{utils.Int64ToStr(c), utils.Int64ToStr(k)}
			dao.ExecuteSQL(db, sql2, param...)
		}
	}
	return nil
}

// GetTiktokImgList 获取抖音图片链接 whiteImg 白底图,有的商品可能没有白底图随便用一张(创建商品专用,更新商品只考虑更新白底图,不然太慢了)
func GetTiktokImgList(api *tiktokShop.API, storeId string, skuId int, detailImg, whiteImg string, img []string) (string, string, string, error) {
	detailTiktok := ""
	whiteTiktok := ""
	tiktokImgLocal, err := dao.GetVendorImg(skuId, model.VendorIDDD)
	if err == nil && tiktokImgLocal != nil && tiktokImgLocal.Img != "" {
		localImgs := make([]string, 0, 0)
		localImgs = append(localImgs, tiktokImgLocal.Img)
		whiteTiktok = tiktokImgLocal.Img
		if tiktokImgLocal.Img2 != "" {
			localImgs = append(localImgs, tiktokImgLocal.Img2)
		}
		if tiktokImgLocal.Img3 != "" {
			localImgs = append(localImgs, tiktokImgLocal.Img3)
		}
		if tiktokImgLocal.Img4 != "" {
			localImgs = append(localImgs, tiktokImgLocal.Img4)
		}
		if tiktokImgLocal.Img5 != "" {
			localImgs = append(localImgs, tiktokImgLocal.Img5)
		}
		if tiktokImgLocal.DescImg != "" {
			detailTiktok = tiktokImgLocal.DescImg
		} else {
			detailTiktok = tiktokImgLocal.Img
		}
		return strings.Join(localImgs, "|"), detailTiktok, whiteTiktok, nil
	}

	imgs := make([]tiktokShop.Imgs, 0, 0)
	for _, v := range img {
		if v != "" {
			imgs = append(imgs, tiktokShop.Imgs{
				Name: storeId + "_" + v[21:54],
				Url:  v,
			})
		}
	}
	if detailImg != "" {
		imgs = append(imgs, tiktokShop.Imgs{
			Name: "detail_" + storeId + "_" + detailImg[21:54],
			Url:  detailImg,
		})
	}
	if whiteImg != "" {
		imgs = append(imgs, tiktokShop.Imgs{
			Name: "white_" + storeId + "_" + whiteImg[21:54],
			Url:  whiteImg,
		})
	}
	tiktokImgList, err := api.BatchUploadImages(imgs)
	if err != nil {
		return "", "", "", err
	}
	if len(tiktokImgList) == model.NO {
		return "", "", "", errors.New("图片上传异常,返回为空")
	}

	var tiktokImg []string
	var localTiktokObj = &model.TaoSkuImg{
		SkuID:    skuId,
		VendorID: model.VendorIDDD,
	}
	for k, v := range tiktokImgList {
		if strings.Contains(k, "detail_") {
			detailTiktok = v.ByteUrl
			localTiktokObj.DescImg = v.ByteUrl
			tiktokImg = append(tiktokImg, v.ByteUrl)
			continue
		}
		if strings.Contains(k, "white_") {
			whiteTiktok = v.ByteUrl
			localTiktokObj.Img = v.ByteUrl
			tiktokImg = append(tiktokImg, v.ByteUrl)
			continue
		}
	}

	switch len(tiktokImg) {
	case 2:
		localTiktokObj.Img2 = tiktokImg[0]
		localTiktokObj.Img3 = tiktokImg[1]
	case 3:
		localTiktokObj.Img2 = tiktokImg[0]
		localTiktokObj.Img3 = tiktokImg[1]
		localTiktokObj.Img4 = tiktokImg[2]
	case 4:
		localTiktokObj.Img2 = tiktokImg[0]
		localTiktokObj.Img3 = tiktokImg[1]
		localTiktokObj.Img4 = tiktokImg[2]
		localTiktokObj.Img5 = tiktokImg[3]
	}
	if localTiktokObj.Img == "" && localTiktokObj.Img2 == "" && localTiktokObj.Img3 == "" && localTiktokObj.Img4 == "" && localTiktokObj.Img5 == "" {
		return "", "", "", errors.New("图片数据为空")
	}
	dao.CreateEntity(dao.GetDB(), localTiktokObj)
	return strings.Join(tiktokImg, "|"), detailTiktok, whiteTiktok, nil
}

func MakeProductFormatNew(api *tiktokShop.API, skuNameId int64, categoryLeafId int64, upcCode, upcBrandName, upcTiktokBrandId string) (string, int64, error) {
	db := dao.GetDB()
	categoryList, err := api.GetCatePropertyV2(categoryLeafId)
	if err != nil {
		return "", 0, err
	}
	categoryMap := make(map[string][]map[string]interface{})
	tiktokBrandId, _ := getTiktokBrandId(api, db, upcCode, upcBrandName, upcTiktokBrandId, categoryLeafId)
	for _, v := range categoryList.Data.Data {
		if v.Required != model.YES {
			continue
		}
		options := make([]map[string]interface{}, 0)
		if v.PropertyName == "品牌" {
			options = append(options, map[string]interface{}{"name": v.PropertyName, "value": tiktokBrandId, "diy_type": v.DiyType})
			categoryMap[utils.Int64ToStr(v.PropertyId)] = options
		} else if v.PropertyName == "产地" {
			options = append(options, map[string]interface{}{"name": v.PropertyName, "value": 13850, "diy_type": v.DiyType})
			categoryMap[utils.Int64ToStr(v.PropertyId)] = options
		} else if v.PropertyName == "生鲜储存温度" {
			options = append(options, map[string]interface{}{"name": v.PropertyName, "value": 2808, "diy_type": v.DiyType})
			categoryMap[utils.Int64ToStr(v.PropertyId)] = options
		} else if len(v.Options) == 0 {
			options = append(options, map[string]interface{}{"name": v.PropertyName, "value": 0, "diy_type": v.DiyType})
			categoryMap[utils.Int64ToStr(v.PropertyId)] = options
		} else {
			options = append(options, map[string]interface{}{"name": v.PropertyName, "value": utils.Str2Int64(v.Options[0].Value), "diy_type": v.DiyType})
			categoryMap[utils.Int64ToStr(v.PropertyId)] = options
		}
	}
	productFormatNew := utils.Format4Output(categoryMap, false)
	dao.UpdateSkuNameTiktokAttr(dao.GetDB(), skuNameId, productFormatNew)
	return utils.Format4Output(categoryMap, false), tiktokBrandId, nil
}

// GetSpecPrices 解析属性和规格参数
func GetSpecPrices(specs, storeId string, mainSkuId int64, localSku *dao.StoreSkuSyncInfo) string {
	skuSize := make([]*tiktokShop.SpecDetailList, 0, 0)
	detail1 := strings.Split(specs, "^")
	if len(detail1) > 3 {
		detail1 = detail1[0:3]
	}
	specsUnit := "g"
	var infoValue float64 = 1                       // 同意计量单位,目前抖店只支持g
	var specQuality = float64(localSku.SpecQuality) // 可能SpecQuality为0,给默认值
	switch localSku.SpecUnit {
	case "g", "G", "ml", "ML":
		specsUnit = "g"
		infoValue = 1
	case "l", "L", "KG", "kg":
		specsUnit = "g"
		infoValue = 1000
	}
	if specQuality == 0 {
		specQuality = 1
	}
	switch len(detail1) {
	case 1:
		name1 := strings.Split(strings.Split(detail1[0], "|")[1], ",")
		for i := 0; i < len(name1); i++ {
			sku := &tiktokShop.SpecDetailList{
				SpecDetailName1: name1[i],
				Price:           int(localSku.VendorPrice),
				Code:            utils.Int2Str(localSku.SkuID),
				StepStockNum:    0,
				SupplierID:      "",
				OuterSkuID:      utils.Int2Str(localSku.SkuID),
			}

			sku.DeliveryInfos = []*tiktokShop.DeliveryInfos{
				{InfoType: "weight", InfoUnit: specsUnit, InfoValue: utils.Float64ToStr(specQuality * infoValue)},
			}
			stock := localSku.Stock
			if localSku.Stock == 0 && beego.BConfig.RunMode != model.ServerTypePet {
				stock = 99999
			}
			sku.StockNum = stock
			sku.SkuType = 1
			sku.StockNumMap = map[string]int64{storeId: int64(stock)}
			skuSize = append(skuSize, sku)
		}
	case 2:
		name1 := strings.Split(strings.Split(detail1[0], "|")[1], ",")
		name2 := strings.Split(strings.Split(detail1[1], "|")[1], ",")
		for i := 0; i < len(name1); i++ {
			for j := 0; j < len(name2); j++ {
				sku := &tiktokShop.SpecDetailList{
					SpecDetailName1: name1[i],
					SpecDetailName2: name2[j],
					Price:           int(localSku.UnitPrice),
					Code:            utils.Int2Str(localSku.SkuID),
					StepStockNum:    0,
					SupplierID:      "",
					OuterSkuID:      utils.Int2Str(localSku.NameID),
					DeliveryInfos: []*tiktokShop.DeliveryInfos{
						{InfoType: "weight", InfoUnit: specsUnit, InfoValue: utils.Float64ToStr(specQuality * infoValue)},
					},
				}
				stock := localSku.Stock
				if localSku.Stock == 0 && beego.BConfig.RunMode != model.ServerTypePet {
					stock = 99999
				}
				sku.StockNum = stock
				sku.SkuType = 1
				sku.StockNumMap = map[string]int64{storeId: int64(stock)}
				skuSize = append(skuSize, sku)
			}
		}
	case 3:
		name1 := strings.Split(strings.Split(detail1[0], "|")[1], ",")
		name2 := strings.Split(strings.Split(detail1[1], "|")[1], ",")
		name3 := strings.Split(strings.Split(detail1[2], "|")[1], ",")
		for i := 0; i < len(name1); i++ {
			for j := 0; j < len(name2); j++ {
				for k := 0; k < len(name3); k++ {
					sku := &tiktokShop.SpecDetailList{
						SpecDetailName1: name1[i],
						SpecDetailName2: name2[j],
						SpecDetailName3: name3[k],
						Price:           int(localSku.UnitPrice),
						Code:            utils.Int2Str(localSku.SkuID),
						StepStockNum:    0,
						SupplierID:      "",
						OuterSkuID:      utils.Int2Str(localSku.NameID),
						DeliveryInfos: []*tiktokShop.DeliveryInfos{
							{InfoType: "weight", InfoUnit: specsUnit, InfoValue: utils.Float64ToStr(specQuality * infoValue)},
						},
					}
					stock := localSku.Stock
					if localSku.Stock == 0 && beego.BConfig.RunMode != model.ServerTypePet {
						stock = 99999
					}
					sku.StockNum = stock
					sku.SkuType = 1
					sku.StockNumMap = map[string]int64{storeId: int64(stock)}
					skuSize = append(skuSize, sku)
				}
			}
		}
	}

	data, _ := json.Marshal(skuSize)
	return string(data)
}

func vendorSku2Jx(tiktokSku *product_detail_response.ProductDetailData) (skuName *partner.SkuNameInfo) {
	if len(tiktokSku.SpecPrices) == 0 {
		return nil
	}
	prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(tiktokSku.Name)
	vendorSku := tiktokSku.SpecPrices[0]
	weight := jxutils.FormatSkuWeight(specQuality, specUnit)

	skuName = &partner.SkuNameInfo{
		NameID:       utils.Str2Int(vendorSku.OuterSkuId),
		VendorNameID: utils.Int64ToStr(tiktokSku.MainProductId),
		UPC:          tiktokSku.ProductIdStr,
		Prefix:       prefix,
		Name:         name,
		Unit:         unit,
		Status:       tiktokSkuStatus2Jx(tiktokSku.Status), //此处为之前一个bug 如果吧状态放到切片内层  对于内层函数中映射无法关联 永远获取到的初始值为0
		SkuList: []*partner.SkuInfo{
			&partner.SkuInfo{
				StoreSkuInfo: partner.StoreSkuInfo{
					VendorSkuID: utils.Int64ToStr(vendorSku.SkuId),
					SkuID:       int(vendorSku.OutSkuId),
					IsSpecialty: 0,
					Stock:       int(vendorSku.StockNum),
					VendorPrice: vendorSku.Price,
					Status:      tiktokSkuStatus2Jx(tiktokSku.Status),
				},
				SkuName:     tiktokSku.Name,
				Comment:     comment,
				SpecQuality: float64(specQuality),
				SpecUnit:    specUnit,
				Weight:      weight,
			},
		},
		PictureList: tiktokSku.Pic,
	}
	if tiktokSku.CategoryDetail != nil {
		// todo, 因为当前我们用的是分类名操作这种方式，所以要返回分类名（而不是分类code）
		skuName.VendorCatIDList = []string{tiktokSku.CategoryDetail.FirstCname, tiktokSku.CategoryDetail.SecondCname, tiktokSku.CategoryDetail.ThirdCname, tiktokSku.CategoryDetail.FourthCname}
	}
	return skuName
}

func tiktokSkuStatus2Jx(skuStatus int64) (jxSkuStatus int) {
	if skuStatus == mtwmapi.SellStatusOnline {
		jxSkuStatus = model.SkuStatusNormal
	} else {
		jxSkuStatus = model.SkuStatusDontSale
	}
	return jxSkuStatus
}

func getStoreVendorOrgCode(storeID int) (vendorOrgCode string) {
	if storeMap, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDDD, ""); storeMap != nil {
		return storeMap.VendorOrgCode
	}
	return vendorOrgCode
}

func convertVendorCatList(remoteCats []*tiktokShop.RetailCategoryInfo) (cats []*partner.BareCategoryInfo) {
	for _, rCat := range remoteCats {
		cat := &partner.BareCategoryInfo{
			VendorCatID: utils.Int64ToStr(rCat.Id),
			Name:        rCat.Name,
			Level:       int(rCat.Level),
			Seq:         0,
			Children:    convertVendorCatList(rCat.Children),
		}
		if cat.VendorCatID == "" {
			cat.VendorCatID = rCat.Name
		}
		cats = append(cats, cat)
	}
	return cats
}
