package putils

import (
	"fmt"
	"sort"
	"time"

	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/model"

	"git.rosy.net.cn/baseapi/utils"
	"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/dao"
	"git.rosy.net.cn/jx-callback/business/partner"
)

type DefSingleStorePlatform struct {
	partner.ISingleStoreStoreSkuHandler
}

func (p *DefSingleStorePlatform) DeleteStoreAllSkus(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error) {
	skuNameList, err := p.GetStoreSkusFullInfo(ctx, parentTask, storeID, vendorStoreID, nil)
	if err != nil || len(skuNameList) == 0 {
		return err
	}
	storeStoreList := make([]*partner.StoreSkuInfo, len(skuNameList))
	for k, v := range skuNameList {
		storeStoreList[k] = &partner.StoreSkuInfo{
			SkuID:       v.SkuList[0].SkuID,
			VendorSkuID: v.SkuList[0].VendorSkuID,
		}
	}
	_, err = FreeBatchStoreSkuInfo("删除门店商品", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
		_, err = p.DeleteStoreSkus(ctx, storeID, vendorStoreID, batchedStoreSkuList)
		return nil, 0, err
	}, ctx, parentTask, storeStoreList, p.GetStoreSkusBatchSize(partner.FuncDeleteStoreSkus), isContinueWhenError)
	return err
}

func (p *DefSingleStorePlatform) DeleteStoreAllCategories(ctx *jxcontext.Context, parentTask tasksch.ITask, storeID int, vendorStoreID string, isContinueWhenError bool) (err error) {
	catList, err := p.GetStoreAllCategories(ctx, storeID, vendorStoreID)
	if err != nil {
		return err
	}
	catListMap := make(map[int][]*partner.BareCategoryInfo)
	flattedCatList := flatCatList(catList)
	for _, v := range flattedCatList {
		catListMap[v.Level] = append(catListMap[v.Level], v)
	}
	var levelList []int
	for k := range catListMap {
		levelList = append(levelList, k)
	}
	sort.Sort(sort.Reverse(sort.IntSlice(levelList)))
	task1 := tasksch.NewSeqTask2(fmt.Sprintf("DeleteStoreAllCategories1, vendorStoreID:%s", vendorStoreID), ctx, true,
		func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
			vendorCatIDs := make([]string, len(catListMap[levelList[step]]))
			for k, v := range catListMap[levelList[step]] {
				vendorCatIDs[k] = v.VendorCatID
			}
			err = FreeBatchCategoryIDOp(func(vendorCatID string) (err error) {
				err2 := p.DeleteStoreCategory(ctx, storeID, vendorStoreID, vendorCatID, step)
				return err2
			}, ctx, task, vendorCatIDs, isContinueWhenError)
			return nil, err
		}, len(levelList))
	tasksch.HandleTask(task1, parentTask, true).Run()
	_, err = task1.GetResult(0)
	return err
}

func flatCatList(catList []*partner.BareCategoryInfo) (flattedCatList []*partner.BareCategoryInfo) {
	flattedCatList = append(flattedCatList, catList...)
	for _, v := range catList {
		flattedCatList = append(flattedCatList, flatCatList(v.Children)...)
	}
	return flattedCatList
}

func (p *DefSingleStorePlatform) GetStoreSkusBareInfo(ctx *jxcontext.Context, vendorOrgCode string, parentTask tasksch.ITask, storeID int, vendorStoreID string, inStoreSkuList []*partner.StoreSkuInfo) (outStoreSkuList []*partner.StoreSkuInfo, err error) {
	resultList, err := FreeBatchStoreSkuInfo("获取门店商品信息", func(task tasksch.ITask, batchedStoreSkuList []*partner.StoreSkuInfo) (result interface{}, successCount int, err error) {
		result, err = p.GetStoreSkusFullInfo(ctx, parentTask, storeID, vendorStoreID, batchedStoreSkuList)
		return result, successCount, err
	}, ctx, parentTask, inStoreSkuList, p.GetStoreSkusBatchSize(partner.FuncGetStoreSkusFullInfo), true)
	if err != nil || len(resultList) == 0 {
		return nil, err
	}
	inStoreSkuMap := make(map[string]*partner.StoreSkuInfo)
	for _, v := range inStoreSkuList {
		if v.VendorSkuID != "" {
			inStoreSkuMap[v.VendorNameID] = v
		}
	}
	for _, v := range resultList {
		skuName := v.(*partner.SkuNameInfo)
		for _, v2 := range skuName.SkuList {
			storeSkuBareInfo := &v2.StoreSkuInfo
			if storeSkuBareInfo.SkuID == 0 && inStoreSkuMap[storeSkuBareInfo.VendorSkuID] != nil {
				storeSkuBareInfo.SkuID = inStoreSkuMap[storeSkuBareInfo.VendorSkuID].SkuID
				storeSkuBareInfo.NameID = inStoreSkuMap[storeSkuBareInfo.VendorSkuID].NameID
			}
			outStoreSkuList = append(outStoreSkuList, storeSkuBareInfo)
		}
	}
	return outStoreSkuList, err
}

func StoreSkuFullList2Bare(storeSkuFull []*partner.SkuNameInfo) (bareStoreSkuList []*partner.StoreSkuInfo) {
	for _, v := range storeSkuFull {
		for _, v2 := range v.SkuList {
			bareStoreSkuList = append(bareStoreSkuList, &v2.StoreSkuInfo)
		}
	}
	return bareStoreSkuList
}

func findCategoryByName(catList []*partner.BareCategoryInfo, catName string) (cat *partner.BareCategoryInfo) {
	catName2 := utils.FilterEmoji(catName)
	for _, v := range catList {
		if v.Name == catName || v.Name == catName2 {
			cat = v
			break
		}
		if cat = findCategoryByName(v.Children, catName); cat != nil {
			break
		}
	}
	return cat
}
func (p *DefSingleStorePlatform) GetStoreCategory(ctx *jxcontext.Context, storeID int, vendorStoreID, catName string) (cat *partner.BareCategoryInfo, err error) {
	catList, err := p.GetStoreAllCategories(ctx, storeID, vendorStoreID)
	if err == nil {
		if cat = findCategoryByName(catList, catName); cat == nil {
			err = fmt.Errorf("门店:%d,%s不能找到商家分类:%s", storeID, vendorStoreID, catName)
		}
	}
	return cat, err
}

func FreeBatchStoreSkuInfo(name string, handler func(tasksch.ITask, []*partner.StoreSkuInfo) (interface{}, int, error), ctx *jxcontext.Context, parentTask tasksch.ITask, storeSkuList []*partner.StoreSkuInfo, batchSize int, isContinueWhenError bool) (resultList []interface{}, err error) {
	if true { //len(storeSkuList) > batchSize {
		task := tasksch.NewParallelTask2(fmt.Sprintf("FreeBatchStoreSkuInfo:%s", name), tasksch.NewParallelConfig().SetParallelCount(1).SetBatchSize(batchSize).SetIsContinueWhenError(isContinueWhenError), ctx,
			func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, successCount int, err error) {
				batchStoreSkuList := make([]*partner.StoreSkuInfo, len(batchItemList))
				for k, v := range batchItemList {
					batchStoreSkuList[k] = v.(*partner.StoreSkuInfo)
				}
				retVal, successCount, err = handler(task, batchStoreSkuList)
				if err != nil {
					retVal = nil
				}
				return retVal, successCount, err
			}, storeSkuList)
		tasksch.HandleTask(task, parentTask, false).Run()
		resultList, err = task.GetResult(0)
	} else {
		result, _, err2 := handler(parentTask, storeSkuList)
		if err = err2; err == nil {
			resultList = utils.Interface2Slice(result)
		}
	}
	return resultList, err
}

func FreeBatchStoreSkuSyncInfo(name string, handler func(tasksch.ITask, []*dao.StoreSkuSyncInfo) (interface{}, int, error), ctx *jxcontext.Context, parentTask tasksch.ITask, storeSkuList []*dao.StoreSkuSyncInfo, batchSize int, isContinueWhenError bool) (resultList []interface{}, err error) {
	if true { //len(storeSkuList) > batchSize {
		task := tasksch.NewParallelTask2(fmt.Sprintf("FreeBatchStoreSkuSyncInfo:%s", name), tasksch.NewParallelConfig().SetParallelCount(1).SetBatchSize(batchSize).SetIsContinueWhenError(isContinueWhenError), ctx,
			func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, successCount int, err error) {
				batchStoreSkuList := make([]*dao.StoreSkuSyncInfo, len(batchItemList))
				for k, v := range batchItemList {
					batchStoreSkuList[k] = v.(*dao.StoreSkuSyncInfo)
				}
				retVal, successCount, err = handler(task, batchStoreSkuList)
				if err != nil {
					retVal = nil
				}
				return retVal, successCount, err
			}, storeSkuList)
		tasksch.HandleTask(task, parentTask, false).Run()
		resultList, err = task.GetResult(0)
	} else {
		result, _, err2 := handler(parentTask, storeSkuList)
		if err = err2; err == nil {
			resultList = utils.Interface2Slice(result)
		}
	}
	return resultList, err
}

func FreeBatchCategoryIDOp(handler func(vendorCatID string) (err error), ctx *jxcontext.Context, parentTask tasksch.ITask, vendorCatIDs []string, isContinueWhenError bool) (err error) {
	if len(vendorCatIDs) > 1 {
		task := tasksch.NewParallelTask("FreeBatchCategoryIDOp", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(isContinueWhenError), ctx,
			func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				err = handler(batchItemList[0].(string))
				return nil, err
			}, vendorCatIDs)
		tasksch.HandleTask(task, parentTask, false).Run()
		_, err = task.GetResult(0)
	} else if len(vendorCatIDs) > 0 {
		err = handler(vendorCatIDs[0])
	}
	return err
}

func StoreSkuList2MapByVendorSkuID(storeSkuList []*partner.StoreSkuInfo) (storeSkuMap map[string]*partner.StoreSkuInfo) {
	storeSkuMap = make(map[string]*partner.StoreSkuInfo)
	for _, v := range storeSkuList {
		storeSkuMap[v.VendorSkuID] = v
	}
	return storeSkuMap
}

func StoreSkuList2MapBySkuID(storeSkuList []*partner.StoreSkuInfo) (storeSkuMap map[int]*partner.StoreSkuInfo) {
	storeSkuMap = make(map[int]*partner.StoreSkuInfo)
	for _, v := range storeSkuList {
		storeSkuMap[v.SkuID] = v
	}
	return storeSkuMap
}

func StoreSkuList2IDs(storeSkuList []*partner.StoreSkuInfo) (ids []int) {
	ids = make([]int, len(storeSkuList))
	for k, v := range storeSkuList {
		ids[k] = v.SkuID
	}
	return ids
}

func UnselectStoreSkuListByVendorSkuIDs(storeSkuList []*partner.StoreSkuInfo, vendorSkuIDs []string) (selectedStoreSkuList []*partner.StoreSkuInfo) {
	if len(vendorSkuIDs) > 0 {
		vendorSkuIDMap := jxutils.StringList2Map(vendorSkuIDs)
		for _, v := range storeSkuList {
			if vendorSkuIDMap[v.VendorSkuID] == 0 {
				selectedStoreSkuList = append(selectedStoreSkuList, v)
			}
		}
	} else {
		selectedStoreSkuList = storeSkuList
	}
	return selectedStoreSkuList
}

func GetErrMsg2FailedSingleList(storeSkuList interface{}, err error, storeID int, vendorName, syncType string) (failedList []*partner.StoreSkuInfoWithErr) {
	if err != nil {
		var errMsg string
		if errExt, ok := err.(*utils.ErrorWithCode); ok {
			errMsg = errExt.ErrMsg()
		} else {
			errMsg = err.Error()
		}
		if storeSkuLists, ok := storeSkuList.([]*partner.StoreSkuInfo); ok {
			storeSkuInfoWithErr := &partner.StoreSkuInfoWithErr{
				StoreSkuInfo: storeSkuLists[0],
				ErrMsg:       errMsg,
				StoreID:      storeID,
				VendoreName:  vendorName,
				SyncType:     syncType,
			}
			failedList = append(failedList, storeSkuInfoWithErr)
		} else if storeSku, ok := storeSkuList.(*partner.StoreSkuInfo); ok {
			storeSkuInfoWithErr := &partner.StoreSkuInfoWithErr{
				StoreSkuInfo: storeSku,
				ErrMsg:       errMsg,
				StoreID:      storeID,
				VendoreName:  vendorName,
				SyncType:     syncType,
			}
			failedList = append(failedList, storeSkuInfoWithErr)
		} else if storeSkuLists, ok := storeSkuList.([]*dao.StoreSkuSyncInfo); ok {
			storeSkuInfo := &partner.StoreSkuInfo{
				SkuID:        storeSkuLists[0].SkuID,
				VendorSkuID:  storeSkuLists[0].VendorSkuID,
				NameID:       storeSkuLists[0].NameID,
				VendorNameID: storeSkuLists[0].VendorNameID,
				VendorPrice:  storeSkuLists[0].VendorPrice,
				Status:       storeSkuLists[0].Status,
			}
			storeSkuInfoWithErr := &partner.StoreSkuInfoWithErr{
				StoreSkuInfo: storeSkuInfo,
				ErrMsg:       errMsg,
				StoreID:      storeID,
				VendoreName:  vendorName,
				SyncType:     syncType,
			}
			failedList = append(failedList, storeSkuInfoWithErr)
		} else if storeSku, ok := storeSkuList.(*dao.StoreSkuSyncInfo); ok {
			storeSkuInfo := &partner.StoreSkuInfo{
				SkuID:        storeSku.SkuID,
				VendorSkuID:  storeSku.VendorSkuID,
				NameID:       storeSku.NameID,
				VendorNameID: storeSku.VendorNameID,
				VendorPrice:  storeSku.VendorPrice,
				Status:       storeSku.Status,
			}
			storeSkuInfoWithErr := &partner.StoreSkuInfoWithErr{
				StoreSkuInfo: storeSkuInfo,
				ErrMsg:       errMsg,
				StoreID:      storeID,
				VendoreName:  vendorName,
				SyncType:     syncType,
			}
			failedList = append(failedList, storeSkuInfoWithErr)
		} else {
			storeSkuInfoWithErr := &partner.StoreSkuInfoWithErr{
				ErrMsg:      errMsg,
				StoreID:     storeID,
				VendoreName: vendorName,
				SyncType:    syncType,
			}
			failedList = append(failedList, storeSkuInfoWithErr)
		}
	}
	return failedList
}

func UnselectStoreSkuSyncListByVendorSkuIDs(storeSkuList []*dao.StoreSkuSyncInfo, vendorSkuIDs []string) (selectedStoreSkuList []*dao.StoreSkuSyncInfo) {
	if len(vendorSkuIDs) > 0 {
		vendorSkuIDMap := jxutils.StringList2Map(vendorSkuIDs)
		for _, v := range storeSkuList {
			if vendorSkuIDMap[v.VendorSkuID] == 0 {
				selectedStoreSkuList = append(selectedStoreSkuList, v)
			}
		}
	} else {
		selectedStoreSkuList = storeSkuList
	}
	return selectedStoreSkuList
}

func UnselectStoreSkuListBySkuIDs(storeSkuList []*partner.StoreSkuInfo, skuIDs []int) (selectedStoreSkuList []*partner.StoreSkuInfo) {
	if len(skuIDs) > 0 {
		skuIDMap := jxutils.IntList2Map(skuIDs)
		for _, v := range storeSkuList {
			if skuIDMap[v.SkuID] == 0 {
				selectedStoreSkuList = append(selectedStoreSkuList, v)
			}
		}
	} else {
		selectedStoreSkuList = storeSkuList
	}
	return selectedStoreSkuList
}

func GenPartialFailedErr(failedInfo interface{}, failedCount int) (err error) {
	if failedCount > 0 {
		err = fmt.Errorf("部分失败了%d个：%s", failedCount, utils.Format4Output(failedInfo, true))
	}
	return err
}

func StoreSku2ActStoreSku(syncStatus int8, vendorStoreID string, storeSkuList []*partner.StoreSkuInfo) (actStoreSku []*model.ActStoreSku2) {
	for _, v := range storeSkuList {
		actStoreSku = append(actStoreSku, &model.ActStoreSku2{
			ActStoreSku: model.ActStoreSku{
				SkuID: v.SkuID,
				Stock: 200,
			},
			VendorStoreID:  vendorStoreID,
			VendorSkuID:    v.VendorSkuID,
			VendorActID:    v.VendorActID,
			ActualActPrice: v.ActPrice,
			SyncStatus:     syncStatus,
		})
	}
	return actStoreSku
}

func UpdateStoreSkuByActStoreSku(storeSkuList []*partner.StoreSkuInfo, actStoreSku []*model.ActStoreSku2) []*partner.StoreSkuInfo {
	storeSkuMap := StoreSkuList2MapBySkuID(storeSkuList)
	for _, v := range actStoreSku {
		if storeSku := storeSkuMap[v.SkuID]; storeSku != nil {
			storeSku.VendorActID = v.VendorActID
		}
	}
	return storeSkuList
}

func GetFixDirectDownAct(vendorOrgCode string, storeID, skuID int) (act *model.Act2) {
	name := fmt.Sprintf("自动直降活动%d:%d:%d", storeID, skuID, time.Now().Unix())
	act = &model.Act2{
		Act: model.Act{
			Name:        name,
			Advertising: name,
			Type:        model.ActSkuDirectDown,
			Status:      model.ActStatusCreated,
			LimitUser:   1,
			LimitCount:  1,
			BeginAt:     utils.Time2Date(time.Now()),
			EndAt:       utils.Time2Date(time.Now().Add(50 * 24 * time.Hour)), // 饿百平台要求只能是2个月长的活动
		},
		VendorOrgCode: vendorOrgCode,
	}
	return act
}

func StoreSkuInfoWithErrList2SkuIDs(list []*partner.StoreSkuInfoWithErr) (skuIDs []int) {
	for _, v := range list {
		if v.StoreSkuInfo != nil && v.StoreSkuInfo.SkuID > 0 {
			skuIDs = append(skuIDs, v.StoreSkuInfo.SkuID)
		}
	}
	return skuIDs
}

func StoreSkuInfoWithErrList2MapBySku(list []*partner.StoreSkuInfoWithErr) (mapInfo map[int]*partner.StoreSkuInfoWithErr) {
	mapInfo = make(map[int]*partner.StoreSkuInfoWithErr)
	for _, v := range list {
		mapInfo[v.StoreSkuInfo.SkuID] = v
	}
	return mapInfo
}
