package controllers

import (
	"fmt"
	"git.rosy.net.cn/jx-callback/business/jxutils/jxcontext"
	"github.com/panjf2000/ants"
	"io"
	"sync"

	"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/model"
	"git.rosy.net.cn/jx-callback/business/model/dao"
	"github.com/astaxie/beego/server/web"
)

type SyncController struct {
	web.Controller
}

// @Title 同步商家商品信息
// @Description 同步商家商品信息
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		formData	string	true	"门店ID列表"
// @Param	vendorIDs		formData	string	true	"厂商ID列表"
// @Param	skuIDs			formData	string	false	"SKU ID列表，缺省为全部"
// @Param	isForce			formData	bool	false	"是否强制（设置修改标志）"
// @Param	isAsync			formData	bool	true	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncStoresSkus [put]
func (c *SyncController) SyncStoresSkus() {
	c.callSyncStoresSkus(func(params *tSyncSyncStoresSkusParams) (retVal interface{}, errCode string, err error) {
		db := dao.GetDB()
		var storeIDs, skuIDs, vendorIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.SkuIDs, &skuIDs, params.VendorIDs, &vendorIDs); err != nil {
			return retVal, "", err
		}
		retVal, err = cms.CurVendorSync.SyncStoresSkus(params.Ctx, nil, 0, db, vendorIDs, storeIDs, skuIDs, params.IsForce, params.IsAsync, params.IsContinueWhenError)
		return retVal, "", err
	})
}

// @Title 同步商家分类信息
// @Description 同步商家分类信息
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		formData	string	true	"门店ID列表"
// @Param	vendorIDs		formData	string	true	"厂商ID列表"
// @Param	isForce			formData	bool	false	"是否强制（设置修改标志）"
// @Param	isAsync			formData	bool	true	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncStoresCategory [put]
func (c *SyncController) SyncStoresCategory() {
	c.callSyncStoresCategory(func(params *tSyncSyncStoresCategoryParams) (retVal interface{}, errCode string, err error) {
		db := dao.GetDB()
		var storeIDs, vendorIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err != nil {
			return retVal, "", err
		}
		retVal, err = cms.CurVendorSync.SyncStoresCategory(params.Ctx, db, vendorIDs, storeIDs, params.IsForce, params.IsAsync, params.IsContinueWhenError)
		return retVal, "", err
	})
}

// @Title 全部刷新所有门店商家ID
// @Description 全部刷新所有门店商家ID
// @Param	token			header		string	true	"认证token"
// @Param	vendorIDs		query		string	true	"需要刷新的厂商ID列表"
// @Param	isAsync			query		bool	false	"起始状态"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /RefreshAllStoresID [put]
func (c *SyncController) RefreshAllStoresID() {
	c.callRefreshAllStoresID(func(params *tSyncRefreshAllStoresIDParams) (retVal interface{}, errCode string, err error) {
		var vendorIDs []int
		if err = utils.UnmarshalUseNumber([]byte(params.VendorIDs), &vendorIDs); err != nil {
			return retVal, "", err
		}
		retVal, err = cms.CurVendorSync.RefreshAllStoresID(params.Ctx, params.IsAsync, vendorIDs)
		return retVal, "", err
	})
}

// @Title 重新刷新商家SKU ID
// @Description 重新刷新商家SKU ID，单门店厂商必须指定storeIDs
// @Param	token			header		string	true	"认证token"
// @Param	vendorIDs		query		string	true	"需要刷新的厂商ID列表"
// @Param	storeIDs		query		string	false	"需要刷新的门店ID列表（对于单门店必须指定）"
// @Param	isAsync			query		bool	false	"起始状态"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /RefreshAllSkusID [put]
// func (c *SyncController) RefreshAllSkusID() {
// 	c.callRefreshAllSkusID(func(params *tSyncRefreshAllSkusIDParams) (retVal interface{}, errCode string, err error) {
// 		var vendorIDs, storeIDs []int
// 		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err != nil {
// 			return retVal, "", err
// 		}
// 		retVal, err = cms.CurVendorSync.RefreshAllSkusID(params.Ctx, params.IsAsync, vendorIDs, storeIDs)
// 		return retVal, "", err
// 	})
// }

// @Title 全新初始化商家商品信息
// @Description 全新初始化商家商品信息（！！！此操作会先清除平台上已有的商品及分类信息），此操作只适用于单门店模式平台
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		formData	string	true	"门店ID列表"
// @Param	vendorIDs		formData	string	true	"厂商ID列表"
// @Param	isAsync			formData	bool	true	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /FullSyncStoresSkus [put]
func (c *SyncController) FullSyncStoresSkus() {
	c.callFullSyncStoresSkus(func(params *tSyncFullSyncStoresSkusParams) (retVal interface{}, errCode string, err error) {
		db := dao.GetDB()
		var vendorIDs, storeIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err != nil {
			return retVal, "", err
		}
		retVal, err = cms.CurVendorSync.FullSyncStoresSkus(params.Ctx, db, vendorIDs, storeIDs, true, nil, params.IsAsync, params.IsContinueWhenError, false)
		return retVal, "", err
	})
}

// @Title 比较门店中后台商品和运营商后台商品的差异 导出一个Excel 表格
// @Description 由于目前同步会因为类别不同会导致商品每晚无法成功同步 因此在同步功能前新增一个导出查看差异功能 比较商品类别
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		formData	string	true	"门店ID列表"
// @Param	vendorIDs		formData	string	true	"厂商ID列表"
// @Param	isAsync			formData	bool	true	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /CompareStoreWithOperator [put]
func (c *SyncController) CompareStoreWithOperator() {
	c.callCompareStoreWithOperator(func(params *tSyncCompareStoreWithOperatorParams) (retVal interface{}, errCode string, err error) {
		var vendorIDs, storeIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err != nil {
			return retVal, "", err
		}
		p, _ := ants.NewPoolWithFunc(10, func(data interface{}) {
			task := data.(*CompareTask)
			task.Do()
		})
		defer p.Release()
		var wg sync.WaitGroup
		wg.Add(len(storeIDs))
		tasks := make([]*CompareTask, 0, len(storeIDs))
		for i := 0; i < len(storeIDs); i++ {
			task := &CompareTask{
				StoreId:  storeIDs[i],
				VendorId: vendorIDs[0],
				Ctx:      params.Ctx,
				Wg:       &wg,
			}

			tasks = append(tasks, task)
			p.Invoke(task)
		}
		wg.Wait()
		//	err = cms.GetVendorStoreSkusToStruct(params.Ctx, storeIDs[0], vendorIDs[0])
		return retVal, "", err
	})
}

type CompareTask struct {
	StoreId  int
	VendorId int
	Ctx      *jxcontext.Context
	Wg       *sync.WaitGroup
}

func (t *CompareTask) Do() {
	cms.GetVendorStoreSkusToStruct(t.Ctx, t.StoreId, t.VendorId)
	t.Wg.Done()
}

// @Title 删除门店平台商品信息（包括分类）
// @Description 删除门店平台商品信息（包括分类）（！！！此操作会先清除平台上已有的商品及分类信息），此操作只适用于单门店模式平台
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		query	string	true	"门店ID列表"
// @Param	vendorIDs		query	string	true	"厂商ID列表"
// @Param	isAsync			query	bool	true	"是否异步操作"
// @Param	isContinueWhenError	query	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /DeleteRemoteStoreSkus [delete]
func (c *SyncController) DeleteRemoteStoreSkus() {
	c.callDeleteRemoteStoreSkus(func(params *tSyncDeleteRemoteStoreSkusParams) (retVal interface{}, errCode string, err error) {
		db := dao.GetDB()
		var vendorIDs, storeIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err != nil {
			return retVal, "", err
		}
		retVal, err = cms.CurVendorSync.DeleteRemoteStoreSkus(params.Ctx, db, vendorIDs, storeIDs, params.IsAsync, params.IsContinueWhenError)
		return retVal, "", err
	})
}

// @Title 同步门店
// @Description 同步门店
// @Param	token			header		string	true	"认证token"
// @Param	vendorIDs		formData		string	false	"平台ID(京东0 美团1 饿百3)列表"
// @Param	vendorOrgCodes	formData		string	false	"平台账号列表"
// @Param	storeIDs		formData		string	false	"门店ID列表"
// @Param	isForce			formData		bool	false	"是否强制（设置修改标志）"
// @Param	isAsync			formData		bool	false	"是否异步"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncStores [post]
func (c *SyncController) SyncStores() {
	c.callSyncStores(func(params *tSyncSyncStoresParams) (retVal interface{}, errCode string, err error) {
		var vendorIDs, storeIDs []int
		var vendorOrgCodes []string
		if err = jxutils.Strings2Objs(params.VendorIDs, &vendorIDs, params.StoreIDs, &storeIDs, params.VendorOrgCodes, &vendorOrgCodes); err == nil {
			db := dao.GetDB()
			if params.IsForce {
				dao.SetStoreMapSyncStatus(db, vendorIDs, storeIDs, model.SyncFlagModifiedMask)
			}
			retVal, err = cms.CurVendorSync.SyncStore2(params.Ctx, db, vendorIDs, storeIDs, true, params.IsAsync)
		}
		return retVal, "", err
	})
}

// @Title 同步商家分类（多门店平台）
// @Description 同步商家分类（多门店平台）
// @Param	token			header		string	true	"认证token"
// @Param	vendorID		formData		int		false	"平台ID(京东0 美团1 饿百3)"
// @Param	vendorOrgCode	formData		string	false	"平台账号"
// @Param	isForce			formData		bool	false	"是否强制（设置修改标志）"
// @Param	isAsync			formData		bool	false	"是否异步"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncCategories [post]
func (c *SyncController) SyncCategories() {
	c.callSyncCategories(func(params *tSyncSyncCategoriesParams) (retVal interface{}, errCode string, err error) {
		var vendorIDs []int
		if params.MapData["vendorID"] != nil {
			vendorIDs = append(vendorIDs, params.VendorID)
		}
		vendorOrgCodes := jxutils.BatchString2Slice(params.VendorOrgCode)
		if params.IsForce {
			dao.SetThingMapSyncStatus(dao.GetDB(), vendorIDs, vendorOrgCodes, model.ThingTypeCategory, nil, model.SyncFlagModifiedMask)
		}
		retVal, err = cms.SyncCategories(params.Ctx, nil, vendorIDs, vendorOrgCodes, nil, params.IsAsync)
		return retVal, "", err
	})
}

// @Title 同步SkuName（多门店平台）
// @Description 同步SkuName（多门店平台）
// @Param	token			header		string	true	"认证token"
// @Param	nameIDs			formData		string	false	"name ID列表"
// @Param	isForce			formData		bool	false	"是否强制（设置修改标志）"
// @Param	vendorID		formData		int		false	"平台ID(京东0 美团1 饿百3)"
// @Param	vendorOrgCode	formData		string	false	"平台账号"
// @Param	isAsync			formData		bool	false	"是否异步"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncSkuNames [put,post]
func (c *SyncController) SyncSkuNames() {
	c.callSyncSkuNames(func(params *tSyncSyncSkuNamesParams) (retVal interface{}, errCode string, err error) {
		var nameIDs []int
		if err = jxutils.Strings2Objs(params.NameIDs, &nameIDs); err == nil {
			var vendorIDs []int
			if params.MapData["vendorID"] != nil {
				vendorIDs = append(vendorIDs, params.VendorID)
			}
			vendorOrgCodes := jxutils.BatchString2Slice(params.VendorOrgCode)
			if params.IsForce {
				dao.SetSkuNameSyncStatus(dao.GetDB(), vendorIDs, vendorOrgCodes, nameIDs, model.SyncFlagModifiedMask)
			}
			retVal, err = cms.SyncSkus(params.Ctx, nil, vendorIDs, vendorOrgCodes, nameIDs, nil, params.IsAsync)
		}
		return retVal, "", err
	})
}

// @Title 删除本地没有的平台门店商品信息
// @Description 删除本地没有的平台门店商品信息（已废弃）
// @Param	token			header		string	true	"认证token"
// @Param	storeIDs		query	string	true	"门店ID列表"
// @Param	vendorIDs		query	string	true	"厂商ID列表"
// @Param	isAsync			query	bool	false	"是否异步操作"
// @Param	isContinueWhenError	query	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /PruneMissingStoreSkus [delete]
func (c *SyncController) PruneMissingStoreSkus() {
	c.callPruneMissingStoreSkus(func(params *tSyncPruneMissingStoreSkusParams) (retVal interface{}, errCode string, err error) {
		var storeIDs, vendorIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err == nil {
			retVal, err = cms.CurVendorSync.PruneMissingStoreSkus(params.Ctx, vendorIDs, storeIDs, params.IsAsync, params.IsContinueWhenError)
		}
		return retVal, "", err
	})
}

// @Title 把京西有，平台无且没有待创建标记的商品加上待创建标记
// @Description 把京西有，平台无且没有待创建标记的商品加上待创建标记（已废弃）
// @Param	token				header			string	true	"认证token"
// @Param	storeIDs			formData		string	false	"门店ID列表"
// @Param	vendorIDs			formData		string	false	"运营商ID列表(京东0 美团1 饿百3)"
// @Param	isAsync				formData		bool	false	"是否异步操作"
// @Param	isContinueWhenError	formData		bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /AddCreateFlagForJxStoreSku [post]
func (c *SyncController) AddCreateFlagForJxStoreSku() {
	c.callAddCreateFlagForJxStoreSku(func(params *tSyncAddCreateFlagForJxStoreSkuParams) (retVal interface{}, errCode string, err error) {
		var storeIDs, vendorIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err == nil {
			retVal, err = cms.CurVendorSync.AddCreateFlagForJxStoreSku(params.Ctx, vendorIDs, storeIDs, params.IsAsync, params.IsContinueWhenError)
		}
		return retVal, "", err
	})
}

// @Title 把京西有，平台无且没有待创建标记的商品加上待创建标记
// @Description 把京西有，平台无且没有待创建标记的商品加上待创建标记
// @Param	token				header			string	true	"认证token"
// @Param	storeIDs			formData		string	false	"门店ID列表"
// @Param	vendorIDs			formData		string	false	"运营商ID列表(京东0 美团1 饿百3)"
// @Param	optType				formData		int		true	"操作方式"
// @Param	isForce				formData		bool	false	"是否强制刷新"
// @Param	isAsync				formData		bool	false	"是否异步操作"
// @Param	isContinueWhenError	formData		bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /AmendAndPruneStoreStuff [post]
func (c *SyncController) AmendAndPruneStoreStuff() {
	c.callAmendAndPruneStoreStuff(func(params *tSyncAmendAndPruneStoreStuffParams) (retVal interface{}, errCode string, err error) {
		var storeIDs, vendorIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs, params.VendorIDs, &vendorIDs); err == nil {
			retVal, err = cms.CurVendorSync.AmendAndPruneStoreStuff(params.Ctx, vendorIDs, storeIDs, params.IsAsync, params.IsContinueWhenError, params.OptType, params.IsForce)
		}
		return retVal, "", err
	})
}

// @Title 初始化多门店平台商品库（及商家分类）
// @Description 初始化多门店平台商品库（及商家分类）
// @Param	token				header			string	true	"认证token"
// @Param	vendorID			formData		int		true	"平台ID(京东0 美团1 饿百3)"
// @Param	vendorOrgCode		formData		string	true	"平台账号"
// @Param	storeID				formData		int		false	"门店ID"
// @Param	isAsync				formData		bool	false	"是否异步操作"
// @Param	isContinueWhenError	formData		bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /FullSyncVendorStuff [post]
func (c *SyncController) FullSyncVendorStuff() {
	c.callFullSyncVendorStuff(func(params *tSyncFullSyncVendorStuffParams) (retVal interface{}, errCode string, err error) {
		retVal, err = cms.FullSyncVendorStuff(params.Ctx, nil, params.StoreID, params.VendorID, params.VendorOrgCode, params.IsAsync, params.IsContinueWhenError)
		return retVal, "", err
	})
}

// @Title 上传假京东门店与SKU映射表（并启动同步）
// @Description 上传假京东门店与SKU映射表（并启动同步）
// @Param	token				header		string	false	"认证token"
// @Param	isSyncNow			formData	bool	false	"是否马上同步，一般不建议"
// @Param	isAsync				formData	bool	false	"是否异步，缺省是同步"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /UploadFakeJdThingMap [post,get]
func (c *SyncController) UploadFakeJdThingMap() {
	if c.Ctx.Input.IsGet() {
		w := c.Ctx.ResponseWriter
		// 上传页面
		w.Header().Add("Content-Type", "text/html")
		w.WriteHeader(200)
		html := `
	<form enctype="multipart/form-data" action="/v2/sync/UploadFakeJdThingMap" method="POST">
	    Send this file: <input name="userfiles" multiple accept="*" type="file" />
		<input type="submit" value="Send File" />
	</form>
	`
		io.WriteString(w, html)
	} else if c.Ctx.Input.IsPost() {
		c.callUploadFakeJdThingMap(func(params *tSyncUploadFakeJdThingMapParams) (retVal interface{}, errCode string, err error) {
			r := c.Ctx.Request
			files := r.MultipartForm.File["userfiles"]
			if len(files) == 0 {
				err = fmt.Errorf("没上传文件")
			} else {
				fileReader, err2 := files[0].Open()
				if err = err2; err == nil {
					retVal, err = cms.UploadFakeJdThingMap(params.Ctx, fileReader, params.IsSyncNow, params.IsAsync, params.IsContinueWhenError)
					fileReader.Close()
				}
			}
			return retVal, "", err
		})
	}
}

// @Title 同步银豹到京西商品
// @Description 同步银豹到京西商品
// @Param	token				header		string	true	"认证token"
// @Param	storeIDs			formData	string	false	"门店ID列表"
// @Param	isAsync				formData	bool	false	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncStoreSkusFromYb [put]
func (c *SyncController) SyncStoreSkusFromYb() {
	c.callSyncStoreSkusFromYb(func(params *tSyncSyncStoreSkusFromYbParams) (retVal interface{}, errCode string, err error) {
		var storeIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs); err == nil {
			retVal, err = cms.CurVendorSync.SyncStoreSkusFromYb(params.Ctx, storeIDs, params.IsAsync, params.IsContinueWhenError)
		}
		return retVal, "", err
	})
}

// @Title 同步京东商城门店商品和库存
// @Description 同步京东商城门店商品和库存
// @Param	token				header		string	true	"认证token"
// @Param	storeIDs			formData	string	false	"门店ID列表"
// @Param	isAsync				formData	bool	false	"是否异步操作"
// @Param	isContinueWhenError	formData	bool	false	"单个同步失败是否继续，缺省false"
// @Success 200 {object} controllers.CallResult
// @Failure 200 {object} controllers.CallResult
// @router /SyncJdsStoresSkus [put]
func (c *SyncController) SyncJdsStoresSkus() {
	c.callSyncJdsStoresSkus(func(params *tSyncSyncJdsStoresSkusParams) (retVal interface{}, errCode string, err error) {
		var storeIDs []int
		if err = jxutils.Strings2Objs(params.StoreIDs, &storeIDs); err == nil {
			retVal, err = cms.CurVendorSync.SyncJdsStoresSkus(params.Ctx, storeIDs, params.IsAsync, params.IsContinueWhenError)
		}
		return retVal, "", err
	})
}
