package yb

import (
	"fmt"
	"regexp"
	"strings"

	"git.rosy.net.cn/baseapi/platformapi/yinbaoapi"
	"git.rosy.net.cn/baseapi/utils"
	"git.rosy.net.cn/jx-callback/business/jxstore/cms"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"
	"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"
	"git.rosy.net.cn/jx-callback/globals/api"
)

var (
	sensitiveWordRegexp = regexp.MustCompile(`商品名称中含有敏感词(\[.*\])`)
)

const (
	addErr1 = "商品已存在"
)

func (p *PurchaseHandler) CreateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		storeSku := storeSkuList[0]
		var result *yinbaoapi.AddProductInfoResult
		flag, err2 := checkYbSku(storeSku) //flag为true表示是标品，标品不用更新称编码
		if err2 != nil {
			err = err2
		} else {
			result, err = api.YinBaoAPI.AddProductInfo(buildProductInfoParam(storeSku))
		}
		if err != nil {
			if errExt, ok := err.(*utils.ErrorWithCode); ok {
				if strings.Contains(errExt.ErrMsg(), addErr1) {
					queryProductByBarcodeResult, _ := api.YinBaoAPI.QueryProductByBarcodes([]string{storeSku.YbBarCode})
					if len(queryProductByBarcodeResult) > 0 {
						api.YinBaoAPI.BatchUpdateProductEnable(vendorStoreID, utils.Int64ToStr(queryProductByBarcodeResult[0].UID), model.SkuStatusNormal)
						storeSku.VendorSkuID = utils.Int64ToStr(queryProductByBarcodeResult[0].UID)
					}
				} else {
					failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "创建商品")
				}
			} else {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "创建商品")
			}
		} else {
			storeSku.VendorSkuID = utils.Int64ToStr(result.UID)
			err = uploadYbImage(vendorStoreID, storeSku.YbBarCode, storeSku.Img)
			if !flag {
				err = updateYbSku(vendorStoreID, storeSku.YbBarCode, nil)
			}
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "创建商品")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) UpdateStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*dao.StoreSkuSyncInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		for _, v := range storeSkuList {
			saveProductParam := &yinbaoapi.SaveProductParam{
				CategoryUid: v.VendorCatID,
			}
			_, err = checkYbSku(v)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "修改商品")
				return failedList, err
			}
			err = updateYbImage(vendorStoreID, v)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "修改商品")
				return failedList, err
			}
			err = updateYbSku(vendorStoreID, v.YbBarCode, saveProductParam)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "修改商品")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) DeleteStoreSkus(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		for _, v := range storeSkuList {
			var productInfo = &yinbaoapi.ProductInfo{
				UID:    utils.Str2Int64(v.VendorSkuID),
				Enable: utils.Int2Pointer(yinbaoapi.SkuStatusDeleted),
			}
			err = api.YinBaoAPI.UpdateProductInfo(productInfo)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "删除商品")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) GetStoreSkusFullInfo(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (skuNameList []*partner.SkuNameInfo, err error) {
	storeDetail, _ := dao.GetStoreDetail(dao.GetDB(), storeID, model.VendorIDYB, "")
	api.YinBaoAPI = yinbaoapi.New(storeDetail.YbAppKey, storeDetail.YbAppID)
	if configs, err := dao.QueryConfigs(dao.GetDB(), "yinbaoCookie", model.ConfigTypeCookie, ""); err == nil {
		yinbaoCookie := configs[0].Value
		api.YinBaoAPI.SetCookie(".POSPALAUTH30220", yinbaoCookie)
	}
	if storeSkuList != nil {
		if len(storeSkuList) == 1 {
			storeSku := storeSkuList[0]
			result, err := api.YinBaoAPI.QueryProductByBarcode(storeSku.VendorSkuID)
			if err != nil || result == nil {
				return nil, err
			}
			resultp, err := api.YinBaoAPI.QueryProductImagesByBarcode(result.Barcode)
			// resultp, err := getProductImages(vendorStoreID, storeSku.VendorSkuID)
			if err != nil {
				return nil, err
			}
			if skuName := vendorSku2Jx(result, resultp); skuName != nil {
				skuNameList = append(skuNameList, skuName)
			}
		} else {
			var barcodes []string
			for _, v := range storeSkuList {
				barcodes = append(barcodes, v.VendorSkuID)
			}
			results, err := api.YinBaoAPI.QueryProductByBarcodes(barcodes)
			if err != nil {
				return nil, err
			}
			for _, v := range results {
				resultp, err := api.YinBaoAPI.QueryProductImagesByBarcode(v.Barcode)
				// resultp, err := getProductImages(vendorStoreID, v.Barcode)
				if err != nil {
					return nil, err
				}
				if skuName := vendorSku2Jx(v, resultp); skuName != nil {
					skuNameList = append(skuNameList, skuName)
				}
			}
		}
	} else {
		result, err := api.YinBaoAPI.QueryProductPages(nil)
		if err != nil {
			return nil, err
		}
		if len(result.Result) < result.PageSize {
			for _, v := range result.Result {
				resultp, err := api.YinBaoAPI.QueryProductImagesByBarcode(v.Barcode)
				// resultp, err := getProductImages(vendorStoreID, v.Barcode)
				if err != nil {
					return nil, err
				}
				vv := &yinbaoapi.QueryProductByBarcodeResult{}
				err = utils.Map2StructByJson(utils.Struct2MapByJson(v), vv, false)
				if skuName := vendorSku2Jx(vv, resultp); skuName != nil {
					skuNameList = append(skuNameList, skuName)
				}
			}
		} else {
			for _, v := range result.Result {
				resultp, err := api.YinBaoAPI.QueryProductImagesByBarcode(v.Barcode)
				// resultp, err := getProductImages(vendorStoreID, v.Barcode)
				if err != nil {
					return nil, err
				}
				vv := &yinbaoapi.QueryProductByBarcodeResult{}
				err = utils.Map2StructByJson(utils.Struct2MapByJson(v), vv, false)
				if skuName := vendorSku2Jx(vv, resultp); skuName != nil {
					skuNameList = append(skuNameList, skuName)
				}
			}
			loopPages(result.PostBackParameter.ParameterType, result.PostBackParameter.ParameterValue, &skuNameList, vendorStoreID)
		}
	}
	return skuNameList, err
}

func getProductImages(vendorStoreID, barCode string) (findProductResult *yinbaoapi.FindProductResult, err error) {
	for {
		ybSkuID, err := api.YinBaoAPI.LoadProductsByPage(vendorStoreID, barCode)
		findProductResult, err = api.YinBaoAPI.FindProduct(ybSkuID)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				findProductResult, err = getProductImages(vendorStoreID, barCode)
			} else {
				break
			}
		}
	}
	return findProductResult, err
}

func (p *PurchaseHandler) UpdateStoreSkusStatus(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo, status int) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		for _, v := range storeSkuList {
			var productInfo = &yinbaoapi.ProductInfo{
				UID:    utils.Str2Int64(v.VendorSkuID),
				Enable: utils.Int2Pointer(ybSkuStatus2Jx(v.Status)),
			}
			err = api.YinBaoAPI.UpdateProductInfo(productInfo)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "更新商品状态")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) UpdateStoreSkusPrice(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		for _, v := range storeSkuList {
			var productInfo = &yinbaoapi.ProductInfo{
				UID:       utils.Str2Int64(v.VendorSkuID),
				SellPrice: utils.Float64ToPointer(jxutils.IntPrice2Standard(v.VendorPrice)),
				BuyPrice:  utils.Float64ToPointer(jxutils.IntPrice2Standard(v.JxPrice)),
			}
			err = api.YinBaoAPI.UpdateProductInfo(productInfo)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "更新商品价格")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) UpdateStoreSkusStock(ctx *jxcontext.Context, vendorOrgCode string, storeID int, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (failedList []*partner.StoreSkuInfoWithErr, err error) {
	if globals.EnableYbStoreWrite {
		for _, v := range storeSkuList {
			var productInfo = &yinbaoapi.ProductInfo{
				UID:   utils.Str2Int64(v.VendorSkuID),
				Stock: utils.Float64ToPointer(utils.Str2Float64(utils.Int2Str(v.Stock))),
			}
			err = api.YinBaoAPI.UpdateProductInfo(productInfo)
			if err != nil {
				failedList = putils.GetErrMsg2FailedSingleList(storeSkuList, err, storeID, model.VendorChineseNames[model.VendorIDYB], "更新商品库存")
			}
		}
	}
	return failedList, err
}

func (p *PurchaseHandler) GetStoreAllCategories(ctx *jxcontext.Context, storeID int, vendorStoreID string) (cats []*partner.BareCategoryInfo, err error) {
	remoteCats, err := loadCategorysWithOption(vendorStoreID)
	cats = convertVendorCatList(remoteCats)
	return cats, err
}

func loadCategorysWithOption(vendorStoreID string) (remoteCats []*yinbaoapi.LoadCategorysWithOptionResult, err error) {
	for {
		remoteCats, err = api.YinBaoAPI.LoadCategorysWithOption(vendorStoreID)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				remoteCats, err = loadCategorysWithOption(vendorStoreID)
			} else {
				break
			}
		}
	}
	return remoteCats, err
}

func (p *PurchaseHandler) CreateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
	if globals.EnableYbStoreWrite {
		var (
			catName       = utils.FilterEmoji(storeCat.Name)
			parentCatName = utils.FilterEmoji(storeCat.ParentCatName)
		)
		vendorCatID, err := addNewCategory(vendorStoreID, catName, parentCatName)
		if err == nil {
			storeCat.VendorCatID = vendorCatID
		}
		return err
	}
	return err
}

func addNewCategory(vendorStoreID, catName, parentCatName string) (vendorCatID string, err error) {
	for {
		vendorCatID, err = api.YinBaoAPI.AddNewCategory(vendorStoreID, catName, parentCatName)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				vendorCatID, err = addNewCategory(vendorStoreID, catName, parentCatName)
			} else {
				break
			}
		}
	}
	return vendorCatID, err
}

func (p *PurchaseHandler) UpdateStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID string, storeCat *dao.SkuStoreCatInfo) (err error) {
	if globals.EnableYbStoreWrite {
		var (
			catName       = utils.FilterEmoji(storeCat.Name)
			parentCatName = utils.FilterEmoji(storeCat.ParentCatName)
		)
		err = updateCategory(vendorStoreID, storeCat.VendorCatID, catName, parentCatName)
	}
	return err
}

func updateCategory(vendorStoreID, vendorCatID, catName, parentCatName string) (err error) {
	for {
		err = api.YinBaoAPI.UpdateCategory(vendorStoreID, vendorCatID, catName, parentCatName)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				err = updateCategory(vendorStoreID, vendorCatID, catName, parentCatName)
			} else {
				break
			}
		}
	}
	return err
}

func (p *PurchaseHandler) DeleteStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, vendorCatID string, level int) (err error) {
	if globals.EnableYbStoreWrite {
		err = deleteCategory(vendorStoreID, []string{vendorCatID})
	}
	return err
}

func deleteCategory(vendorStoreID string, vendorCatIDs []string) (err error) {
	for {
		err = api.YinBaoAPI.DeleteCategory(vendorStoreID, vendorCatIDs)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				err = api.YinBaoAPI.DeleteCategory(vendorStoreID, vendorCatIDs)
			} else {
				break
			}
		}
	}
	return err
}

func (p *PurchaseHandler) IsErrSkuExist(err error) (isExist bool) {
	return yinbaoapi.IsErrSkuExist(err)
}

func (p *PurchaseHandler) IsErrCategoryExist(err error) (isExist bool) {
	return yinbaoapi.IsErrCategoryExist(err)
}

func (p *PurchaseHandler) IsErrCategoryNotExist(err error) (isNotExist bool) {
	return false
}

func (p *PurchaseHandler) GetStoreSkusBatchSize(funcID int) (batchSize int) {
	return 1
}

func (p *PurchaseHandler) GetSensitiveWordRegexp() *regexp.Regexp {
	return sensitiveWordRegexp
}

func (p *PurchaseHandler) IsErrSkuNotExist(err error) (isNotExist bool) {
	return yinbaoapi.IsErrSkuNotExist(err)
}

func (p *PurchaseHandler) GetSkuCategoryIdByName(vendorOrgCode, skuName string) (vendorCategoryId string, err error) {
	return "", err
}
func ybSkuStatus2Jx(ybStatus int) (jxSkuStatus int) {
	if ybStatus == yinbaoapi.SkuStatusEnable {
		jxSkuStatus = model.SkuStatusNormal
	} else if ybStatus == yinbaoapi.SkuStatusDisabled {
		jxSkuStatus = model.SkuStatusDontSale
	} else if ybStatus == yinbaoapi.SkuStatusDeleted {
		jxSkuStatus = model.SkuStatusDeleted
	}
	return jxSkuStatus
}

func vendorSku2Jx(result *yinbaoapi.QueryProductByBarcodeResult, resultp []*yinbaoapi.QueryProductImagesByBarcodeResult) (skuName *partner.SkuNameInfo) {
	var picList []string
	if result == nil {
		return nil
	}
	if len(resultp) > 0 {
		if resultp[0].ImageURL != "" {
			// for _, v := range resultp.Productimages {
			picList = append(picList, resultp[0].ImageURL)
			// }
		}
	}
	prefix, name, comment, specUnit, unit, specQuality := jxutils.SplitSkuName(result.Name)
	skuName = &partner.SkuNameInfo{
		Prefix:    prefix,
		Name:      name,
		Unit:      unit,
		YbBarCode: result.Barcode,
		SkuList: []*partner.SkuInfo{
			&partner.SkuInfo{
				StoreSkuInfo: partner.StoreSkuInfo{
					VendorSkuID: utils.Int64ToStr(result.UID),
					Stock:       int(utils.Float64TwoInt64(result.Stock)),
					VendorPrice: jxutils.StandardPrice2Int(result.SellPrice),
					Status:      ybSkuStatus2Jx(result.Enable),
				},
				SkuName:     result.Name,
				Comment:     comment,
				SpecQuality: float64(specQuality),
				SpecUnit:    specUnit,
				Weight:      int(utils.Float64TwoInt64(float64(specQuality))),
			},
		},
		PictureList: picList,
	}
	return skuName
}

func loopPages(parameterType, parameterValue string, skuNameList *[]*partner.SkuNameInfo, vendorStoreID string) (err error) {
	var postBackParameter = &yinbaoapi.PostBackParameter{
		ParameterType:  parameterType,
		ParameterValue: parameterValue,
	}
	resultPages, err := api.YinBaoAPI.QueryProductPages(postBackParameter)
	if err != nil {
		return err
	}
	for _, v := range resultPages.Result {
		// resultp, err := api.YinBaoAPI.QueryProductImagesByBarcode(v.Barcode)
		// resultp, err := getProductImages(vendorStoreID, v.Barcode)
		if err != nil {
			return err
		}
		var resultp []*yinbaoapi.QueryProductImagesByBarcodeResult
		vv := &yinbaoapi.QueryProductByBarcodeResult{}
		err = utils.Map2StructByJson(utils.Struct2MapByJson(v), vv, false)
		if skuName := vendorSku2Jx(vv, resultp); skuName != nil {
			*skuNameList = append(*skuNameList, skuName)
		}
	}
	if len(resultPages.Result) >= resultPages.PageSize {
		err = loopPages(resultPages.PostBackParameter.ParameterType, resultPages.PostBackParameter.ParameterValue, skuNameList, vendorStoreID)
	}
	return err
}

func buildProductInfoParam(storeSku *dao.StoreSkuSyncInfo) (productInfoParam *yinbaoapi.ProductInfoParam) {
	var (
		buyPrice  float64 = utils.Str2Float64(utils.Int64ToStr(storeSku.Price)) / 100
		sellPrice float64 = utils.Str2Float64(utils.Int64ToStr(storeSku.VendorPrice)) / 100
		// _, name, _, _, _, _         = jxutils.SplitSkuName()
	)
	productInfoParam = &yinbaoapi.ProductInfoParam{}
	productInfo := &yinbaoapi.ProductInfo{
		Stock:       utils.Float64ToPointer(utils.Str2Float64(utils.Int2Str(model.MaxStoreSkuStockQty))),
		Name:        storeSku.Name,
		Barcode:     storeSku.YbBarCode,
		BuyPrice:    &buyPrice,
		SellPrice:   &sellPrice,
		CategoryUID: utils.Str2Int64(storeSku.VendorCatID),
	}
	productInfoParam.ProductInfo = productInfo
	return productInfoParam
}

func convertVendorCatList(remoteCats []*yinbaoapi.LoadCategorysWithOptionResult) (cats []*partner.BareCategoryInfo) {
	for _, rCat := range remoteCats {
		cat := &partner.BareCategoryInfo{
			VendorCatID: rCat.TxtUID,
			Name:        rCat.Name,
		}
		if rCat.TxtParentUID == "" {
			cat.Level = 1
		} else {
			cat.Level = 2
		}
		cats = append(cats, cat)
	}
	return cats
}

func updateYbSku(vendorStoreID, ybBarCode string, saveProductParam *yinbaoapi.SaveProductParam) (err error) {
	for {
		err = api.YinBaoAPI.SaveProduct(vendorStoreID, ybBarCode, saveProductParam)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				err = updateYbSku(vendorStoreID, ybBarCode, saveProductParam)
			} else {
				break
			}
		}
	}
	return err
}

func checkYbSku(storeSku *dao.StoreSkuSyncInfo) (flag bool, err error) {
	skuID := storeSku.SkuID
	skus, _ := dao.GetSkus(dao.GetDB(), []int{skuID}, nil, nil, nil, nil)
	if len(skus) > 0 {
		if skus[0].Unit != model.UnitNames[0] {
			flag = true
			if skus[0].Upc == "" {
				return flag, fmt.Errorf("标品必须指定upc码，skuID[%v]", skuID)
			} else {
				storeSku.YbBarCode = skus[0].Upc
			}
		}
	}
	return flag, err
}

func uploadYbImage(vendorStoreID, ybBarCode, img string) (err error) {
	ybSkuID, err := api.YinBaoAPI.LoadProductsByPage(vendorStoreID, ybBarCode)
	resBinary, _, err := jxutils.DownloadFileByURL(img)
	fileName := img[strings.LastIndex(img, "/")+1:]
	err = uploadYbImageLoop(vendorStoreID, ybSkuID, resBinary, fileName)
	return err
}

func uploadYbImageLoop(vendorStoreID, ybSkuID string, resBinary []byte, fileName string) (err error) {
	for {
		err = api.YinBaoAPI.UploadProductImage(vendorStoreID, ybSkuID, resBinary, fileName)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				err = uploadYbImageLoop(vendorStoreID, ybSkuID, resBinary, fileName)
			} else {
				break
			}
		}
	}
	return err
}

func updateYbImage(vendorStoreID string, v *dao.StoreSkuSyncInfo) (err error) {
	err = uploadYbImage(vendorStoreID, v.YbBarCode, v.Img)
	err = resetCoverImageLoop(vendorStoreID, v.YbBarCode)
	return err
}

func resetCoverImageLoop(vendorStoreID, ybBarCode string) (err error) {
	for {
		err = api.YinBaoAPI.ResetCoverImage(vendorStoreID, ybBarCode)
		if err == nil {
			break
		} else {
			if yinbaoapi.IsErrCookie(err) {
				err = cms.ChangeYbCookie()
				if err != nil {
					break
				}
				err = resetCoverImageLoop(vendorStoreID, ybBarCode)
			} else {
				break
			}
		}
	}
	return err
}
