package yonghui

import (
	"errors"
	"fmt"
	"io"
	"math"
	"mime/multipart"
	"strings"
	"sync"
	"time"

	"git.rosy.net.cn/baseapi"
	"git.rosy.net.cn/baseapi/utils"
	"github.com/360EntSecGroup-Skylar/excelize"

	"git.rosy.net.cn/baseapi/platformapi/dingdingapi"
	"git.rosy.net.cn/baseapi/platformapi/jdapi"
	"git.rosy.net.cn/baseapi/platformapi/weimobapi"
	"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/ddmsg"
	"git.rosy.net.cn/jx-callback/business/jxutils/excel"
	"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/globals"

	"git.rosy.net.cn/jx-callback/globals/api"
)

type SheetParam struct {
	SkuIDCol       int
	SkuPriceCol    int
	SkuNameCol     int
	OrgSkuIdCol    int
	OrgSkuPriceCol int
	OrgSkuNameCol  int
	SkuRow         int
}

type DataStoreSkusSuccessLock struct {
	dataStoreSkusSuccessList []DataStoreSkusSuccess
	locker                   sync.RWMutex
}

type DataSuccessLock struct {
	dataSuccessList []DataSuccess
	locker          sync.RWMutex
}

type DataFailedLock struct {
	dataFailedList []DataFailed
	locker         sync.RWMutex
}

type DataStoreSkusSuccess struct {
	StoreID  int     `json:"门店ID"`
	NameID   int     `json:"商品编码"`
	Name     string  `json:"商品名称"`
	Unit     string  `json:"单位"`
	OrgPrice float64 `json:"原价"`
	NowPrice float64 `json:"现价"`
	MixPrice float64 `json:"涨跌"`
}

type DataSuccess struct {
	NameID   string  `json:"商品编码"`
	Name     string  `json:"商品名称"`
	Unit     string  `json:"单位"`
	OrgPrice float64 `json:"原价"`
	NowPrice float64 `json:"现价"`
	MixPrice float64 `json:"涨跌"`
}

type DataFailed struct {
	GoodsID   string `json:"商品ID"`
	GoodsName string `json:"商品名称"`
	Comment   string `json:"备注"`
}

type Data struct {
	GoodsID   string `json:"商品编码"`
	GoodsName string `json:"商品名称"`
	GoodsNum  int    `json:"订货数量"`
}

type ExcelParam struct {
	SpuCode string
	Name    string
	Price   float64
}

type OrderList struct {
	Name    string `json:"name"`
	Phone   string `json:"phone"`
	OrderNo int64  `json:"orderNo"`
}

type WeimobOrderSkusExcelResult struct {
	DownloadUrlFine  string `json:"downloadUrlFine,omitempty"`
	DownloadUrlHairy string `json:"downloadUrlHairy,omitempty"`
}

var (
	sheetMap = map[string]*SheetParam{
		"蔬菜": &SheetParam{
			SkuIDCol:       0,
			SkuPriceCol:    14,
			SkuNameCol:     1,
			OrgSkuIdCol:    5,
			OrgSkuPriceCol: 8,
			OrgSkuNameCol:  6,
			SkuRow:         2,
		}, "水果": &SheetParam{
			SkuIDCol:       0,
			SkuPriceCol:    14,
			SkuNameCol:     1,
			OrgSkuIdCol:    5,
			OrgSkuPriceCol: 8,
			OrgSkuNameCol:  6,
			SkuRow:         2,
		}, "肉禽": &SheetParam{
			SkuIDCol:       0,
			SkuPriceCol:    12,
			SkuNameCol:     1,
			OrgSkuIdCol:    4,
			OrgSkuPriceCol: 7,
			OrgSkuNameCol:  5,
			SkuRow:         1,
		}, "净配": &SheetParam{
			SkuIDCol:       0,
			SkuPriceCol:    14,
			SkuNameCol:     1,
			OrgSkuIdCol:    4,
			OrgSkuPriceCol: 7,
			OrgSkuNameCol:  5,
			SkuRow:         1,
		}, "水产": &SheetParam{
			SkuIDCol:       1,
			SkuPriceCol:    15,
			SkuNameCol:     2,
			OrgSkuIdCol:    6,
			OrgSkuPriceCol: 9,
			OrgSkuNameCol:  7,
			SkuRow:         1,
		}, "干货": &SheetParam{
			SkuIDCol:       0,
			SkuPriceCol:    13,
			SkuNameCol:     1,
			OrgSkuIdCol:    4,
			OrgSkuPriceCol: 7,
			OrgSkuNameCol:  5,
			SkuRow:         2,
		}, "MINI肉禽价格": &SheetParam{
			SkuIDCol:       1,
			SkuPriceCol:    5,
			SkuNameCol:     2,
			OrgSkuIdCol:    -1,
			OrgSkuPriceCol: -1,
			OrgSkuNameCol:  -1,
			SkuRow:         1,
		},
	}
	titleListStoreSkusSuccess = []string{
		"门店ID",
		"商品编码",
		"商品名称",
		"单位",
		"原价",
		"现价",
		"涨跌",
	}
	titleListSuccess = []string{
		"商品编码",
		"商品名称",
		"单位",
		"原价",
		"现价",
		"涨跌",
	}
	titleListFailed = []string{
		"商品ID",
		"商品名称",
		"备注",
	}
	titleList = []string{
		"商品编码",
		"商品名称",
		"订货数量",
	}
	dataSuccess          DataSuccessLock
	dataFailed           DataFailedLock
	dataStoreSkusSuccess DataStoreSkusSuccessLock
)

const (
	parallelCount               = 5
	UpdateGoodsShelfStatusCount = 50 //微盟下架商品api限制一次50个
)

func (d *DataSuccessLock) AppendData(dataSuccess DataSuccess) {
	d.locker.Lock()
	defer d.locker.Unlock()
	d.dataSuccessList = append(d.dataSuccessList, dataSuccess)
}

func (d *DataFailedLock) AppendData2(dataFailed DataFailed) {
	d.locker.Lock()
	defer d.locker.Unlock()
	d.dataFailedList = append(d.dataFailedList, dataFailed)
}

func (d *DataStoreSkusSuccessLock) AppendData3(dataStoreSkusSuccess DataStoreSkusSuccess) {
	d.locker.Lock()
	defer d.locker.Unlock()
	d.dataStoreSkusSuccessList = append(d.dataStoreSkusSuccessList, dataStoreSkusSuccess)
}

func LoadExcelByYongHui(ctx *jxcontext.Context, files []*multipart.FileHeader, isAsync, isContinueWhenError bool) (hint string, err error) {
	if len(files) == 0 {
		return "", errors.New("没有文件上传！")
	}
	fileHeader := files[0]
	file, err := fileHeader.Open()
	hint, err = LoadExcelBinByYongHui(ctx, file, true, true)
	file.Close()
	return hint, err
}

func LoadExcelBinByYongHui(ctx *jxcontext.Context, reader io.Reader, isAsync, isContinueWhenError bool) (hint string, err error) {
	var (
		skuMap                = make(map[string]*ExcelParam)
		costPrice             float64 //成本价
		goodsList             []*weimobapi.GoodsInfo
		goodsIDListForPutAway []interface{}
		isCompare             bool
		isExecute             = false
	)
	db := dao.GetDB()
	taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
		var errMsg string
		switch step {
		case 0:
			//读取excel文件
			xlsx, err := excelize.OpenReader(reader)
			if err != nil {
				return "", err
			}
			for k := range sheetMap {
				sheetParam := sheetMap[k]
				rows, _ := xlsx.GetRows(k)
				for rowNum, row := range rows {
					errMsg += GetCellIntoMap(sheetParam, skuMap, row, k, rowNum)
				}
			}
			//修改分组名
			// 分类名格式为：可定XX日
			// XX为上传永辉 提供的 价格表时间 +2天
			if errMsg == "" {
				isExecute = true
			} else {
				return "", fmt.Errorf(errMsg)
			}
			if isExecute {
				isCompare, err = UpdateClassifyAndGetLastClassify()
			}
		case 1:
			//获取微盟所有商品
			param := &weimobapi.QueryGoodsListParam{
				PageNum:  1,
				PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds,
			}
			goodsList, err = GetWeiMobGoodsList(param)
			if err != nil {
				baseapi.SugarLogger.Errorf("GetWeiMobGoodsList error:%v", err)
			}
			taskFunc2 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				v := batchItemList[0].(*weimobapi.GoodsInfo)
				goodsDetail, err := api.WeimobAPI.QueryGoodsDetail(v.GoodsID)
				if err != nil {
					baseapi.SugarLogger.Errorf("QueryGoodsDetail error:%v", err)
				}
				v.GoodsDetailInfo = goodsDetail
				return retVal, err
			}
			taskParallel2 := tasksch.NewParallelTask("获取微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc2, goodsList)
			tasksch.HandleTask(taskParallel2, task, true).Run()
			_, err = taskParallel2.GetResult(0)
			//找出excel上有，微盟没有的,有就列出报错，不进行更新
			goodsInfoAndDetailMap := GetGoodsInfoAndDetailMap(goodsList)
			for k, _ := range skuMap {
				//表示excel上有，微盟上没有
				if goodsInfoAndDetailMap[k] == nil {
					outPutData := DataFailed{
						GoodsID:   k,
						GoodsName: skuMap[k].Name,
						Comment:   "在微盟上未找到该商品",
					}
					dataFailed.AppendData2(outPutData)
				}
			}
		case 2:
			//找出微盟上有，excel上没有的，有就更新，没有就下架
			taskFunc3 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				goods := batchItemList[0].(*weimobapi.GoodsInfo)
				goodsDetail := goods.GoodsDetailInfo
				spuCode := goodsDetail.OuterGoodsCode
				if spuCode != "" {
					//如果微盟商品里找得到excel中的商品
					if skuMap[spuCode] != nil {
						//获取京西库商品
						skuList, _ := dao.GetSkus(db, nil, []int{int(utils.Str2Int64(goodsDetail.SkuMap.SingleSku.OuterSkuCode))}, nil, nil, nil)
						if len(skuList) == 0 {
							outPutData := DataFailed{
								GoodsID:   spuCode,
								GoodsName: skuMap[spuCode].Name,
								Comment:   "在京西库中未找到该商品",
							}
							dataFailed.AppendData2(outPutData)
						} else {
							if skuList[0].Unit == "份" {
								if goodsDetail.SkuMap.SingleSku.B2CSku.Weight == 0 {
									costPrice = skuMap[spuCode].Price
								} else {
									costPrice = Float64Round(0.5 / goodsDetail.SkuMap.SingleSku.B2CSku.Weight * skuMap[spuCode].Price)
								}
							} else {
								costPrice = skuMap[spuCode].Price
							}
							if isExecute {
								_, _, _ = updateWeiMobGoods(costPrice, skuMap[spuCode].Price, skuList[0].Unit, isCompare, goodsDetail)
							}
						}
					} else {
						//下架微盟商品
						retVal = []int64{goodsDetail.GoodsID}
					}
				}
				return retVal, err
			}
			taskParallel3 := tasksch.NewParallelTask("根据获取的微盟所有商品并更新", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc3, goodsList)
			tasksch.HandleTask(taskParallel3, task, true).Run()
			goodsIDListForPutAwayInterface, err2 := taskParallel3.GetResult(0)
			if err = err2; err != nil {
				return "", err
			}
			goodsIDListForPutAway = goodsIDListForPutAwayInterface
		case 3:
			// 批量下架微盟商品
			taskFunc4 := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				int64Slice := []int64{}
				for _, v := range batchItemList {
					int64Slice = append(int64Slice, v.(int64))
				}
				if isExecute {
					PutAwayWeiMobSku(int64Slice)
				}
				return retVal, err
			}
			taskParallel4 := tasksch.NewParallelTask("下架微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount).SetBatchSize(UpdateGoodsShelfStatusCount), ctx, taskFunc4, goodsIDListForPutAway)
			tasksch.HandleTask(taskParallel4, task, true).Run()
			_, err = taskParallel4.GetResult(0)
		case 4:
			WriteToExcel(task, dataSuccess.dataSuccessList, dataFailed.dataFailedList)
		}

		return result, err
	}
	taskSeq := tasksch.NewSeqTask2("读取永辉Excel文件修改微盟商品价格可售状态-序列任务", ctx, isContinueWhenError, taskSeqFunc, 5)
	tasksch.HandleTask(taskSeq, nil, true).Run()
	if !isAsync {
		_, err = taskSeq.GetResult(0)
		hint = "1"
	} else {
		hint = taskSeq.GetID()
	}
	return hint, err
}

func PutAwayWeiMobSku(goodsIDListForPutAway []int64) (err error) {
	if globals.EnableStoreWrite {
		err = api.WeimobAPI.UpdateGoodsShelfStatus(goodsIDListForPutAway, false)
	}
	if err != nil {
		baseapi.SugarLogger.Errorf("UpdateGoodsShelfStatus error:%v", err)
	}
	return err
}

func GetGoodsInfoAndDetailMap(goodsList []*weimobapi.GoodsInfo) (goodsMap map[string]*weimobapi.GoodsInfo) {
	goodsMap = make(map[string]*weimobapi.GoodsInfo)
	for _, v := range goodsList {
		goodsMap[v.GoodsDetailInfo.OuterGoodsCode] = v
	}
	return goodsMap
}

func updateWeiMobGoods(costPrice, salePrice float64, unit string, isCompare bool, goodsDetail *weimobapi.GoodsDetailInfo) (goodsID int64, skuMap map[string]int64, err error) {
	var (
		categoryList          []*weimobapi.CategoryList
		skuListInfo           = goodsDetail.SkuList[0]
		skuListParam          []*weimobapi.SkuList
		categoryID            int
		deliveryTypeListSlice []int64
		newSkuTitle           string
	)

	//查询配送方式
	deliveryTypeList, err := api.WeimobAPI.FindDeliveryTypeList(goodsDetail.GoodsID)
	if err != nil {
		baseapi.SugarLogger.Errorf("FindDeliveryTypeList error:%v", err)
	}
	for _, deliveryType := range deliveryTypeList {
		if deliveryType.Selected {
			deliveryTypeListSlice = append(deliveryTypeListSlice, deliveryType.DeliveryID)
		}
	}
	//查询运费模板
	freightTemplateListInfo, err := api.WeimobAPI.FindFreightTemplateList(goodsDetail.GoodsID)
	if err != nil {
		baseapi.SugarLogger.Errorf("FindFreightTemplateList error:%v", err)
	}

	//寻找分类子ID
	categoryList = goodsDetail.CategoryList
	if len(categoryList) > 0 {
		categoryID = categoryList[len(categoryList)-1].CategoryID
	} else {
		return 0, nil, errors.New(fmt.Sprintf("未查询到此商品的分类信息！goodsID : [%v] ,", goodsDetail.GoodsID))
	}

	//商品分组（原有的分组IDs）
	selectedClassifyList := goodsDetail.SelectedClassifyList
	selectedClassifyListIDMap := make(map[int64]int64)
	if len(selectedClassifyList) > 0 {
		for _, v := range selectedClassifyList {
			for _, v := range v.ChildrenClassify {
				selectedClassifyListIDMap[v.ClassifyID] = v.ClassifyID
			}
		}
	}

	//上次上传价格和这次上传价格对比
	// 	4、微盟商品。两个重要分组
	//     降价超0.2元，与前一日数据对比，需要将此类商品增加分类到这里，不改变原分类
	//     涨价超0.2元，与前一日数据对比，需要将此类商品增加分类到这里，不改变原分类
	//     其他商品，取消 这两个分类
	//     同一天第二次上传的处理，需要注意是与前一天价格的对比，不是当天的价格对比。

	// 5. 涨价和跌价值保留2位小数
	//     需要在每个商品中增加↑0.01或↓0.02。
	//     显示在商品最前的括号里，如果没有括号，需要增加。都用小写的括号，大写括号需要删除。
	//     包装菜需要增加“精”，其他不需要加字，比如：
	//    (精↓2.11)新土豆1kg/袋
	//    (↓2.11)新土豆1kg
	//salePrice 这次上传的价格  goodsDetail.SkuMap.SingleSku.SalePrice 上次上传的价格  priceMix 两次上传价格差  priceMixRound 保留两位后的价格差
	if !isCompare {
		priceMix := salePrice - goodsDetail.SkuMap.SingleSku.SalePrice
		if priceMix > 0.2 {
			delete(selectedClassifyListIDMap, 1064198248)
			delete(selectedClassifyListIDMap, 1065246248)
			selectedClassifyListIDMap[1064198248] = 1064198248
		} else if priceMix < -0.2 {
			delete(selectedClassifyListIDMap, 1064198248)
			delete(selectedClassifyListIDMap, 1065246248)
			selectedClassifyListIDMap[1065246248] = 1065246248
		} else {
			delete(selectedClassifyListIDMap, 1064198248)
			delete(selectedClassifyListIDMap, 1065246248)
		}
		priceMixRound := Float64Round(priceMix)
		newSkuTitle = GetNewSkuTitle(priceMixRound, goodsDetail.Title, goodsDetail.OuterGoodsCode)
	} else {
		newSkuTitle = goodsDetail.Title
	}

	b2CSku := &weimobapi.B2CSku{
		Weight: skuListInfo.B2CSku.Weight,
		Volume: skuListInfo.B2CSku.Volume,
	}
	b2CGoods := &weimobapi.B2CGoods{
		B2CGoodsType:       goodsDetail.B2CGoods.B2CGoodsType,
		DeliveryTypeIDList: deliveryTypeListSlice,
		FreightTemplateID:  freightTemplateListInfo.DefaultFreightTemplate.TemplateID,
	}
	skuList := &weimobapi.SkuList{
		SalePrice:    salePrice,
		CostPrice:    costPrice,
		SkuID:        skuListInfo.SkuID,
		EditStockNum: 9999 - skuListInfo.AvailableStockNum,
		OuterSkuCode: skuListInfo.OuterSkuCode,
		B2CSku:       b2CSku,
	}
	skuListParam = append(skuListParam, skuList)
	goods := &weimobapi.Goods{
		B2CGoods:               b2CGoods,
		SkuList:                skuListParam,
		Title:                  newSkuTitle,
		IsMultiSku:             goodsDetail.IsMultiSku,
		IsPutAway:              weimobapi.GoodsTypeNormal,
		GoodsImageURL:          goodsDetail.GoodsImageURL,
		GoodsID:                goodsDetail.GoodsID,
		CategoryID:             categoryID,
		OuterGoodsCode:         goodsDetail.OuterGoodsCode,
		PointDeductRatio:       goodsDetail.PointDeductRatio,
		SelectedClassifyIDList: Map2Int64Slice(selectedClassifyListIDMap),
	}
	updateGoodsParam := &weimobapi.UpdateGoodsParam{
		Goods: goods,
	}
	if globals.EnableStoreWrite {
		goodsID, skuMap, err = api.WeimobAPI.UpdateGoods3(updateGoodsParam)
		if err != nil {
			if errExt, ok := err.(*utils.ErrorWithCode); ok {
				outPutData := DataFailed{
					GoodsID:   goodsDetail.OuterGoodsCode,
					GoodsName: goodsDetail.Title,
					Comment:   errExt.ErrMsg(),
				}
				dataFailed.AppendData2(outPutData)
			}
		} else {
			outPutData := DataSuccess{
				NameID:   goodsDetail.OuterGoodsCode,
				Name:     newSkuTitle,
				Unit:     unit,
				OrgPrice: goodsDetail.SkuMap.SingleSku.SalePrice,
				NowPrice: salePrice,
				MixPrice: Float64Round(salePrice - goodsDetail.SkuMap.SingleSku.SalePrice),
			}
			dataSuccess.AppendData(outPutData)
		}
	}
	return goodsID, skuMap, err
}

func GetWeiMobGoodsList(param *weimobapi.QueryGoodsListParam) (goodsList []*weimobapi.GoodsInfo, err error) {
	for {
		goodsInfoList, _, err := api.WeimobAPI.QueryGoodsList(param)
		if err != nil {
			return nil, err
		}
		if len(goodsInfoList) > 0 {
			goodsList = append(goodsList, goodsInfoList...)
		}
		if len(goodsInfoList) < param.PageSize {
			break
		}
		param.PageNum++
	}
	return goodsList, err
}

func GetCellIntoMap(sheetParam *SheetParam, skuMap map[string]*ExcelParam, row []string, sheetName string, rowNum int) (errMsg string) {
	var (
		skuID          string
		orgSkuID       string
		skuPrice       float64
		orgSkuPrice    float64
		skuName        string
		orgSkuName     string
		skuIDCol       = sheetParam.SkuIDCol
		skuPriceCol    = sheetParam.SkuPriceCol
		skuNameCol     = sheetParam.SkuNameCol
		orgSkuIDCol    = sheetParam.OrgSkuIdCol
		orgSkuPriceCol = sheetParam.OrgSkuPriceCol
		orgSkuNameCol  = sheetParam.OrgSkuNameCol
	)
	for k, cell := range row {
		if cell != "" {
			if k == skuIDCol && skuIDCol >= 0 {
				skuID = cell
			}
			if k == skuPriceCol && skuPriceCol >= 0 {
				if rowNum == sheetParam.SkuRow-1 {
					if !strings.Contains(cell, "今日供价") && !strings.Contains(cell, "单价") {
						errMsg += fmt.Sprintf("sheet页：[%v],Excel排版发生变化！第[%v]列今日供价附近可能增加或减少了一列，请确认！", sheetName, k+1)
					}
				}
				skuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0))
			}
			if k == orgSkuIDCol && orgSkuIDCol >= 0 {
				orgSkuID = "0" + cell
			}
			if k == orgSkuPriceCol && orgSkuPriceCol >= 0 {
				if rowNum == sheetParam.SkuRow-1 {
					if !strings.Contains(cell, "进价") {
						errMsg += fmt.Sprintf("sheet页：[%v],Excel排版发生变化！第[%v]列进价附近可能增加或减少了一列，请确认!", sheetName, k+1)
					}
				}
				orgSkuPrice = Float64Round(utils.Str2Float64WithDefault(cell, 0))
			}
			if k == skuNameCol && skuNameCol >= 0 {
				skuName = cell
			}
			if k == orgSkuNameCol && orgSkuNameCol >= 0 {
				orgSkuName = cell
			}
		}
	}
	if rowNum >= sheetParam.SkuRow {
		if rowNum == sheetParam.SkuRow {
			if cms.IsChineseChar(skuID) {
				errMsg += fmt.Sprintf("sheet页：[%v],Excel排版发生变化！第[%v]行附近可能增加了一行，请确认！", sheetName, rowNum)
			}
		}
		if len(skuMap) > 0 {
			if skuMap[skuID] != nil {
				if skuMap[skuID].Price != 0 && skuMap[skuID].Price != skuPrice && skuPrice != 0 {
					if skuPrice > skuMap[skuID].Price {
						BuildSkuMap(skuID, skuName, skuPrice, skuMap)
					}
				} else {
					BuildSkuMap(skuID, skuName, skuPrice, skuMap)
				}
			} else if skuPrice != 0 {
				BuildSkuMap(skuID, skuName, skuPrice, skuMap)
			}
			if skuMap[orgSkuID] != nil {
				if skuMap[orgSkuID].Price != 0 && skuMap[orgSkuID].Price != orgSkuPrice && orgSkuPrice != 0 {
					if orgSkuPrice > skuMap[orgSkuID].Price {
						BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap)
					}
				} else if orgSkuPriceCol >= 0 && orgSkuIDCol >= 0 && orgSkuNameCol >= 0 {
					BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap)
				}
			} else if orgSkuPrice != 0 {
				BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap)
			}
		} else {
			BuildSkuMap(skuID, skuName, skuPrice, skuMap)
			BuildSkuMap(orgSkuID, orgSkuName, orgSkuPrice, skuMap)
		}
		delete(skuMap, "")
	} else {
		for i := rowNum; i < sheetParam.SkuRow; i++ {
			if !cms.IsChineseChar(skuID) {
				errMsg += fmt.Sprintf("sheet页：[%v],Excel排版发生变化！第[%v]行附近可能减少了一行，请确认！", sheetName, rowNum)
			}
		}
	}
	return errMsg
}
func BuildSkuMap(id, name string, price float64, skuMap map[string]*ExcelParam) {
	excelParam := &ExcelParam{
		SpuCode: id,
		Price:   price,
		Name:    name,
	}
	skuMap[id] = excelParam
}

func Float64Round(f float64) (flt float64) {
	return math.Round(f*100) / 100
}

func Map2Int64Slice(m map[int64]int64) (result []int64) {
	for _, v := range m {
		result = append(result, v)
	}
	return result
}

func UpdateClassifyAndGetLastClassify() (isCompare bool, err error) {
	var lastTitle string
	classfiyList, err := api.WeimobAPI.QueryClassifyInfoList()
	if len(classfiyList) > 0 {
		for _, v := range classfiyList {
			if v.ClassifyID == 1065244148 {
				lastTitle = v.Title
			}
		}
	}
	title := "可定"
	now := time.Now()
	afterDay := now.AddDate(0, 0, 2).Day()
	title += utils.Int2Str(afterDay) + "日"
	if lastTitle == title {
		return true, err
	} else {
		err = api.WeimobAPI.UpdateClassify(1065244148, title, "")
		return false, err
	}
}

func GetNewSkuTitle(priceMixRound float64, orgTitle, outerGoodsCode string) (name string) {
	var prefix = ""
	title1 := strings.ReplaceAll(orgTitle, "（", "(")
	title := strings.ReplaceAll(title1, "）", ")")
	if outerGoodsCode[0:1] != "0" {
		prefix += "(精"
		if priceMixRound > 0 {
			prefix += "↑"
		} else if priceMixRound < 0 {
			prefix += "↓"
		} else {
			prefix += ")"
			return GetReplaceNewTitle(title, prefix)
		}
	} else {
		if priceMixRound > 0 {
			prefix += "(↑"
		} else if priceMixRound < 0 {
			prefix += "(↓"
		} else {
			return GetReplaceNewTitle(title, prefix)
		}
	}
	prefix += utils.Float64ToStr(math.Abs(priceMixRound)) + ")"
	return GetReplaceNewTitle(title, prefix)
}

func GetReplaceNewTitle(title, prefix string) (newTitle string) {
	if title[0:1] == "(" {
		return strings.Replace(title, title[0:strings.Index(title, ")")+1], prefix, 1)
	} else {
		return prefix + title
	}
}

func WriteToExcel(task *tasksch.SeqTask, dataSuccess []DataSuccess, dataFailed []DataFailed) (err error) {
	var sheetList1 []*excel.Obj2ExcelSheetConfig
	var sheetList2 []*excel.Obj2ExcelSheetConfig
	var downloadURL1, downloadURL2, fileName1, fileName2 string
	excelConf1 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        dataSuccess,
		CaptionList: titleListSuccess,
	}
	sheetList1 = append(sheetList1, excelConf1)
	excelConf2 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        dataFailed,
		CaptionList: titleListFailed,
	}
	sheetList2 = append(sheetList2, excelConf2)
	if excelConf1 != nil {
		downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "微盟已更新商品")
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!")
	}
	if excelConf2 != nil {
		downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "缺少商品_微盟")
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: dataFailed is nil!")
	}
	if err != nil {
		baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err)
	} else {
		noticeMsg := fmt.Sprintf("[详情点我]path1=%s, path2=%s  \n", downloadURL1, downloadURL2)
		task.SetNoticeMsg(noticeMsg)
		baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2)
	}
	return err
}

func UpdateJxPriceByWeimob(ctx *jxcontext.Context, storeIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
	var (
		storeSkuBindInfoList []interface{}
		skuBindInfos         []*cms.StoreSkuBindInfo
		nameID               int
	)
	db := dao.GetDB()
	dataFailed.dataFailedList = dataFailed.dataFailedList[0:0]
	dataStoreSkusSuccess.dataStoreSkusSuccessList = dataStoreSkusSuccess.dataStoreSkusSuccessList[0:0]
	//获取微盟所有商品
	param := &weimobapi.QueryGoodsListParam{
		PageNum:  1,
		PageSize: jdapi.MaxSkuIDsCount4QueryListBySkuIds,
	}
	goodsList, err := GetWeiMobGoodsList(param)
	if err != nil {
		baseapi.SugarLogger.Errorf("GetWeiMobGoodsList error:%v", err)
	}
	taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
		switch step {
		case 0:
			taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				v := batchItemList[0].(*weimobapi.GoodsInfo)
				goodsDetail, err := api.WeimobAPI.QueryGoodsDetail(v.GoodsID)
				if err != nil {
					baseapi.SugarLogger.Errorf("QueryGoodsDetail error:%v", err)
				}
				goodsID := goodsDetail.OuterGoodsCode
				unitPrice := int(utils.Float64TwoInt64(goodsDetail.SkuMap.SingleSku.CostPrice * 100))
				if goodsDetail.SkuMap.SingleSku.OuterSkuCode != "" {
					nameID = int(utils.Str2Int64(goodsDetail.SkuMap.SingleSku.OuterSkuCode))
				} else {
					outPutData := DataFailed{
						GoodsID:   goodsID,
						GoodsName: goodsDetail.Title,
						Comment:   "微盟上没有该商品的商品编码",
					}
					dataFailed.AppendData2(outPutData)
					nameID = -1
				}
				skuList, err := dao.GetStoreSkusByNameIDs(db, storeIDs, nameID)
				if len(skuList) > 0 {
					if goodsDetail.OuterGoodsCode != "" {
						if goodsDetail.IsPutAway == weimobapi.GoodsTypeNormal {
							storeSkuBindInfo := &cms.StoreSkuBindInfo{
								NameID:    nameID,
								UnitPrice: unitPrice,
							}
							retVal = []*cms.StoreSkuBindInfo{storeSkuBindInfo}
							for _, v := range skuList {
								outPutData := DataStoreSkusSuccess{
									StoreID:  v.StoreID,
									NameID:   nameID,
									Name:     v.Name,
									Unit:     v.Unit,
									OrgPrice: utils.Str2Float64(utils.Int64ToStr(v.UnitPrice)) / 100,
									NowPrice: goodsDetail.SkuMap.SingleSku.CostPrice,
									MixPrice: Float64Round((utils.Str2Float64(utils.Int64ToStr(v.UnitPrice)) / 100) - goodsDetail.SkuMap.SingleSku.CostPrice),
								}
								dataStoreSkusSuccess.AppendData3(outPutData)
							}
						} else { //如果微盟为下架
							outPutData := DataFailed{
								GoodsID:   goodsID,
								GoodsName: goodsDetail.Title,
								Comment:   "微盟已下架",
							}
							dataFailed.AppendData2(outPutData)
						}
					} else {
						outPutData := DataFailed{
							GoodsID:   goodsID,
							GoodsName: goodsDetail.Title,
							Comment:   "微盟上没有该商品的spu编码",
						}
						dataFailed.AppendData2(outPutData)
					}
				} else {
					outPutData := DataFailed{
						GoodsID:   goodsID,
						GoodsName: goodsDetail.Title,
						Comment:   "京西未关注该商品",
					}
					dataFailed.AppendData2(outPutData)
				}
				return retVal, err
			}
			taskParallel := tasksch.NewParallelTask("获取微盟商品", tasksch.NewParallelConfig().SetParallelCount(parallelCount), ctx, taskFunc, goodsList)
			tasksch.HandleTask(taskParallel, task, true).Run()
			storeSkuBindInfoList, err = taskParallel.GetResult(0)
		case 1:
			for _, v := range storeSkuBindInfoList {
				skuBindInfos = append(skuBindInfos, v.(*cms.StoreSkuBindInfo))
			}
			cms.UpdateStoresSkus(ctx, 0, storeIDs, skuBindInfos, false, false, isAsync, isContinueWhenError)
		case 2:
			WriteToExcel3(task, dataStoreSkusSuccess.dataStoreSkusSuccessList, dataFailed.dataFailedList)
		}
		return result, err
	}
	taskSeq := tasksch.NewSeqTask2("根据微盟商品更新京西价", ctx, isContinueWhenError, taskSeqFunc, 3)
	tasksch.HandleTask(taskSeq, nil, true).Run()
	if !isAsync {
		_, err = taskSeq.GetResult(0)
		hint = "1"
	} else {
		hint = taskSeq.GetID()
	}
	return hint, err
}

func WriteToExcel3(task *tasksch.SeqTask, dataSuccess []DataStoreSkusSuccess, dataFailed []DataFailed) (err error) {
	var sheetList1 []*excel.Obj2ExcelSheetConfig
	var sheetList2 []*excel.Obj2ExcelSheetConfig
	var downloadURL1, downloadURL2, fileName1, fileName2 string
	excelConf1 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        dataSuccess,
		CaptionList: titleListStoreSkusSuccess,
	}
	sheetList1 = append(sheetList1, excelConf1)
	excelConf2 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        dataFailed,
		CaptionList: titleListFailed,
	}
	sheetList2 = append(sheetList2, excelConf2)
	if excelConf1 != nil {
		downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "京西已更新商品")
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: dataSuccess is nil!")
	}
	if excelConf2 != nil {
		downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "缺少商品_京西")
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: dataFailed is nil!")
	}
	if err != nil {
		baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err)
	} else {
		noticeMsg := fmt.Sprintf("[详情点我]path1=%s, path2=%s  \n", downloadURL1, downloadURL2)
		task.SetNoticeMsg(noticeMsg)
		baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2)
	}
	return err
}

func GetWeimobOrders(ctx *jxcontext.Context, fromTime, toTime string, params map[string]interface{}) (result []*OrderList, err error) {
	if fromTime != "" && toTime != "" {
		fromTimeParam := utils.Str2Time(fromTime).UnixNano() / 1e6
		toTimeParam := utils.Str2Time(toTime).UnixNano() / 1e6
		if params["keyword"] != nil {
			if jxutils.GetPossibleVendorIDFromVendorOrderID(params["keyword"].(string)) > model.VendorIDUnknown {
				resultList, err := GetSingleOrderResultList(params)
				result = append(result, resultList...)
				return result, err
			} else {
				orderList, err := GetWeimobOrdersList(fromTimeParam, toTimeParam, params["keyword"].(string))
				return orderList, err
			}
		} else {
			orderList, err := GetWeimobOrdersList(fromTimeParam, toTimeParam, "")
			return orderList, err
		}
	}
	if fromTime == "" && toTime == "" && params["keyword"] != nil {
		if jxutils.GetPossibleVendorIDFromVendorOrderID(params["keyword"].(string)) > model.VendorIDUnknown {
			resultList, err := GetSingleOrderResultList(params)
			result = append(result, resultList...)
			return result, err
		} else {
			orderList, err := GetWeimobOrdersList(0, 0, params["keyword"].(string))
			return orderList, err
		}
	}
	return result, err
}

func GetWeimobOrdersList(fromTimeParam, toTimeParam int64, keyword string) (aList []*OrderList, err error) {
	var queryParameter *weimobapi.MerchantOrderListQueryParameter
	if fromTimeParam == 0 && toTimeParam == 0 {
		queryParameter = &weimobapi.MerchantOrderListQueryParameter{
			CreateStartTime: time.Now().AddDate(0, -2, 0).UnixNano() / 1e6,
			CreateEndTime:   time.Now().UnixNano() / 1e6,
		}
	} else {
		queryParameter = &weimobapi.MerchantOrderListQueryParameter{
			CreateStartTime: fromTimeParam,
			CreateEndTime:   toTimeParam,
		}
	}
	param := &weimobapi.QueryOrdersListParam{
		PageNum:        1,
		PageSize:       weimobapi.QueryOrdersListPageSize,
		QueryParameter: queryParameter,
	}
	for {
		orderList, _, err2 := api.WeimobAPI.QueryOrdersList(param)
		err = err2
		if len(orderList) > 0 {
			if keyword != "" {
				for _, v := range orderList {
					if ContainsKeyword(v, keyword) {
						var aOrder = &OrderList{
							Name:    v.ReceiverName,
							OrderNo: v.OrderNo,
							Phone:   v.ReceiverMobile,
						}
						aList = append(aList, aOrder)
					}
				}
			} else {
				for _, v := range orderList {
					var aOrder = &OrderList{
						Name:    v.ReceiverName,
						OrderNo: v.OrderNo,
						Phone:   v.ReceiverMobile,
					}
					aList = append(aList, aOrder)
				}
			}
		}
		if len(orderList) < param.PageSize {
			break
		}
		param.PageNum++
	}
	return aList, err
}

func GetWeimobOrderDetail(orderNo int64) (order *weimobapi.OrderDetail, err error) {
	order, err = api.WeimobAPI.QueryOrderDetail2(orderNo, false)
	if err != nil {
		return nil, err
	}
	return order, err
}

func GetSingleOrderResultList(params map[string]interface{}) (result []*OrderList, err error) {
	weimobOrderID := params["keyword"].(string)
	orderSingle, err := GetWeimobOrderDetail(utils.Str2Int64(weimobOrderID))
	orderList := &OrderList{
		Name:    orderSingle.DeliveryDetail.LogisticsDeliveryDetail.ReceiverName,
		Phone:   orderSingle.DeliveryDetail.LogisticsDeliveryDetail.ReceiverMobile,
		OrderNo: orderSingle.OrderNo,
	}
	result = append(result, orderList)
	return result, err
}

func ContainsKeyword(v *weimobapi.OrderInfo, keyword string) bool {
	return strings.Contains(v.ReceiverName, keyword) || strings.Contains(utils.Int64ToStr(v.OrderNo), keyword) || strings.Contains(v.ReceiverMobile, keyword)
}

func GetWeimobOrdersExcel(ctx *jxcontext.Context, OrderNo string) (result *WeimobOrderSkusExcelResult, err error) {
	var (
		DataFineList  []*Data //精品
		DataHairyList []*Data //毛菜
	)
	orderSingle, err := GetWeimobOrderDetail(utils.Str2Int64(OrderNo))
	if err != nil {
		return result, err
	}
	if len(orderSingle.ItemList) > 0 {
		itemList := orderSingle.ItemList
		for _, v := range itemList {
			if v.GoodsCode != "" {
				var goodsTile string
				if v.GoodsTitle[0:1] == "(" {
					goodsTile = v.GoodsTitle[strings.Index(v.GoodsTitle, ")")+1 : len(v.GoodsTitle)]
				} else {
					goodsTile = v.GoodsTitle
				}
				if v.GoodsCode[0:1] == "0" {
					DataHairy := &Data{
						GoodsID:   v.GoodsCode[1:len(v.GoodsCode)],
						GoodsName: goodsTile,
						GoodsNum:  v.SkuNum,
					}
					DataHairyList = append(DataHairyList, DataHairy)
				} else {
					DataFine := &Data{
						GoodsID:   v.GoodsCode,
						GoodsName: goodsTile,
						GoodsNum:  v.SkuNum,
					}
					DataFineList = append(DataFineList, DataFine)
				}
			} else {
				return result, errors.New(fmt.Sprintf("此订单中该商品无spu编码，请检查！订单号：[%v] ,商品名: [%v]", OrderNo, v.GoodsTitle))
			}
		}
	} else {
		return result, errors.New(fmt.Sprintf("此订单中无商品信息，请检查！订单号：[%v]", OrderNo))
	}
	downloadURL1, downloadURL2, err := WriteToExcel2(ctx, DataFineList, DataHairyList)
	result = &WeimobOrderSkusExcelResult{
		DownloadUrlFine:  downloadURL1,
		DownloadUrlHairy: downloadURL2,
	}
	return result, err
}

func WriteToExcel2(ctx *jxcontext.Context, DataFineList, DataHairyList []*Data) (downloadURL1, downloadURL2 string, err error) {
	var (
		sheetList1           []*excel.Obj2ExcelSheetConfig
		sheetList2           []*excel.Obj2ExcelSheetConfig
		fileName1, fileName2 string
		noticeMsg            string
	)
	excelConf1 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        DataFineList,
		CaptionList: titleList,
	}
	sheetList1 = append(sheetList1, excelConf1)
	excelConf2 := &excel.Obj2ExcelSheetConfig{
		Title:       "sheet1",
		Data:        DataHairyList,
		CaptionList: titleList,
	}
	sheetList2 = append(sheetList2, excelConf2)
	noticeMsg += "[详情点我]"
	if len(DataFineList) > 0 {
		downloadURL1, fileName1, err = jxutils.UploadExeclAndPushMsg(sheetList1, "京西采购_精品")
		noticeMsg += "path1=" + downloadURL1 + " "
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: DataFineList is nil!")
	}
	if len(DataHairyList) > 0 {
		downloadURL2, fileName2, err = jxutils.UploadExeclAndPushMsg(sheetList2, "京西采购_毛菜")
		noticeMsg += "path2=" + downloadURL2
	} else {
		baseapi.SugarLogger.Debug("WriteToExcel: DataHairyList is nil!")
	}
	if err != nil {
		baseapi.SugarLogger.Errorf("WriteToExcel:upload %s , %s failed error:%v", fileName1, fileName2, err)
	} else {
		if authInfo, err := ctx.GetV2AuthInfo(); err == nil {
			ddmsg.SendUserMessage(dingdingapi.MsgTyeText, authInfo.UserID, "导出微盟订单商品成功", noticeMsg)
			baseapi.SugarLogger.Debugf("WriteToExcel:upload %s ,%s success, downloadURL1:%s ,downloadURL2:%s", fileName1, fileName2, downloadURL1, downloadURL2)
		}
	}
	return downloadURL1, downloadURL2, err
}
