package report

import (
	"errors"
	"fmt"
	"git.rosy.net.cn/jx-callback/business/jxstore/cms"
	"git.rosy.net.cn/jx-callback/globals"
	"git.rosy.net.cn/jx-callback/globals/api"
	"math"
	"sort"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/platformapi/mtwmapi"

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

	"git.rosy.net.cn/jx-callback/business/partner"

	"git.rosy.net.cn/jx-callback/business/jxstore/permission"
	"git.rosy.net.cn/jx-callback/business/jxutils/tasksch"

	"git.rosy.net.cn/baseapi/utils"
	"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"
)

type tStoreSkuBindAndSkuName struct {
	CityCode      int
	StoreID       int `orm:"column(store_id)"`
	NameID        int `orm:"column(name_id)"`
	UnitPrice     int
	UnitPriceList []int
}

func GetStatisticsReportForOrders(ctx *jxcontext.Context, storeIDs, vendorIDs []int, fromDate, toDate, marketPhone, jdPhone, mtPhone, ebaiPhone string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
	db := dao.GetDB()
	fromDateParm := utils.Str2Time(fromDate)
	toDateParm := utils.Str2Time(toDate)
	//若时间间隔大于3个月则不允许查询
	if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
		return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月！: 时间范围：[%v]  至  [%v]", fromDate, toDate))
	}
	if permission.IsRoled(ctx) {
		if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
			var storeIDs2 []int
			if len(storeIDs) != 0 {
				for _, v := range storeIDs {
					if storeIDsMap[v] != 0 {
						storeIDs2 = append(storeIDs2, v)
					}
				}
				if len(storeIDs2) == 0 {
					storeIDs2 = append(storeIDs2, -1)
				}
			} else {
				for k, _ := range storeIDsMap {
					storeIDs2 = append(storeIDs2, k)
				}
				roleInfo, _ := cms.GetUserRoleList(ctx, ctx.GetUserID())
				for _, v := range roleInfo {
					storeIDs2 = append(storeIDs2, v.StoreID)
				}
			}
			storeIDs = storeIDs2
		}
	}

	statisticsReportForOrdersList, err = dao.GetStatisticsReportForOrders(db, storeIDs, vendorIDs, fromDateParm, toDateParm, marketPhone, jdPhone, mtPhone, ebaiPhone)
	return statisticsReportForOrdersList, err
}

func GetStatisticsReportForAfsOrders(ctx *jxcontext.Context, storeIDs []int, fromDate string, toDate string) (statisticsReportForOrdersList []*dao.StatisticsReportForOrdersList, err error) {
	db := dao.GetDB()
	fromDateParm := utils.Str2Time(fromDate)
	toDateParm := utils.Str2Time(toDate)
	//若时间间隔大于3个月则不允许查询
	if math.Ceil(toDateParm.Sub(fromDateParm).Hours()/24) > 92 {
		return nil, errors.New(fmt.Sprintf("查询间隔时间不允许大于3个月！: 时间范围：[%v]  至  [%v]", fromDate, toDate))
	}
	statisticsReportForOrdersList, err = dao.GetGetStatisticsReportForAfsOrders(db, storeIDs, fromDateParm, toDateParm)
	return statisticsReportForOrdersList, err
}

func StatisticsReportForStoreSkusPrice(ctx *jxcontext.Context, cityCodes, skuIDs []int, snapDate string, offset, pageSize int) (pagedInfo *model.PagedInfo, err error) {
	var snapDateParam time.Time
	db := dao.GetDB()
	if snapDate != "" {
		snapDateParam = utils.Str2Time(snapDate)
	}
	priceReferSnapshot, totalCount, err := dao.GetPriceReferSnapshot(db, cityCodes, skuIDs, 0, snapDateParam, offset, pageSize)
	pagedInfo = &model.PagedInfo{
		Data:       priceReferSnapshot,
		TotalCount: totalCount,
	}
	return
}

func BeginSavePriceRefer(ctx *jxcontext.Context, cityCodes, skuIDs []int, isAsync, isContinueWhenError bool) (hint string, err error) {
	var priceReferSnapshotList []*model.PriceReferSnapshot
	db := dao.GetDB()
	snapshotAt := utils.Time2Date(time.Now().AddDate(0, 0, -1))
	dao.DeletePriceReferHistory(db, utils.Time2Date(snapshotAt.AddDate(0, 0, -7)))
	priceReferSnapshotDelete := &model.PriceReferSnapshot{SnapshotAt: snapshotAt}
	dao.DeleteEntity(db, priceReferSnapshotDelete, "SnapshotAt")
	taskSeqFunc := func(task *tasksch.SeqTask, step int, params ...interface{}) (result interface{}, err error) {
		switch step {
		case 0:
			priceReferSnapshot, err := dao.GetStatisticsReportForStoreSkusPrice(db, cityCodes, skuIDs)
			if len(priceReferSnapshot) > 0 {
				txDB, _ := dao.Begin(db)
				defer func() {
					if r := recover(); r != nil || err != nil {
						dao.Rollback(db, txDB)
						if r != nil {
							panic(r)
						}
					}
				}()
				for _, v := range priceReferSnapshot {
					dao.WrapAddIDCULDEntity(v, ctx.GetUserName())
					v.SnapshotAt = snapshotAt
				}
				dao.CreateMultiEntities(db, priceReferSnapshot)
				dao.Commit(db, txDB)
			}
		case 1:
			priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, nil, nil, nil, snapshotAt)
			var (
				citySkuMap       = make(map[int]map[int][]int)
				countryMap       = make(map[int][]int)
				resultMap        = make(map[int]map[int]*model.PriceReferSnapshot)
				resultCountryMap = make(map[int]*model.PriceReferSnapshot)
			)
			storeList, err := dao.GetStoreList(db, nil, nil, nil, nil, nil, "")
			if err != nil {
				return result, err
			}
			for _, v := range storeList {
				if v.PayPercentage < 50 {
					continue
				}
				var tList []*tStoreSkuBindAndSkuName
				sql := `
				SELECT DISTINCT b.city_code, a.store_id, Round(a.unit_price * IF(b.pay_percentage < 50 , 70, b.pay_percentage) / 100) AS unit_price, c.name_id
				FROM store_sku_bind a
				JOIN store b ON b.id = a.store_id AND b.deleted_at = ? AND b.status != ?
				JOIN sku c ON c.id = a.sku_id
				WHERE a.store_id = ? 
				AND c.name_id NOT IN(
				SELECT b.name_id
							FROM store_sku_bind a
							JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
							WHERE a.deleted_at = ?
							AND a.store_id = ?
							AND b.name_id NOT IN(SELECT DISTINCT b.name_id
												FROM store_sku_bind a
												JOIN sku b ON a.sku_id = b.id AND b.deleted_at = ?
												WHERE a.deleted_at = ?
												AND a.store_id = ?
												AND a.status = ?)
												)
				AND a.deleted_at = ?
				`
				sqlParams := []interface{}{
					utils.DefaultTimeValue,
					model.StoreStatusDisabled,
					v.ID,
					utils.DefaultTimeValue,
					utils.DefaultTimeValue,
					v.ID,
					utils.DefaultTimeValue,
					utils.DefaultTimeValue,
					v.ID,
					model.StoreSkuBindStatusNormal,
					utils.DefaultTimeValue,
				}
				dao.GetRows(db, &tList, sql, sqlParams...)
				skuNameMap := make(map[int][]int)
				if len(tList) > 0 {
					for _, vv := range tList {
						skuNameMap[vv.NameID] = append(skuNameMap[vv.NameID], vv.UnitPrice)
						countryMap[vv.NameID] = append(countryMap[vv.NameID], vv.UnitPrice)
					}
					if citySkuMap[v.CityCode] != nil {
						for nameID, unitPriceList := range skuNameMap {
							if citySkuMap[v.CityCode][nameID] != nil {
								citySkuMap[v.CityCode][nameID] = append(citySkuMap[v.CityCode][nameID], unitPriceList...)
							} else {
								citySkuMap[v.CityCode][nameID] = unitPriceList
							}
						}
					} else {
						citySkuMap[v.CityCode] = skuNameMap
					}
				}
			}
			for k, v := range countryMap {
				var midUnitPrice int
				var avgUnitPrice int
				sort.Ints(v)
				if len(v)%2 == 0 {
					midUnitPrice = v[len(v)/2-1]
				} else {
					midUnitPrice = v[len(v)/2]
				}
				for _, vv := range v {
					avgUnitPrice += vv
				}
				priceRefer := &model.PriceReferSnapshot{
					MidUnitPrice: midUnitPrice,
					MaxUnitPrice: v[len(v)-1],
					MinUnitPrice: v[0],
					AvgUnitPrice: avgUnitPrice / len(v),
				}
				resultCountryMap[k] = priceRefer
			}
			for k1, v := range citySkuMap {
				skuNameMap := make(map[int]*model.PriceReferSnapshot)
				for k2, _ := range v {
					var midUnitPrice int
					var avgUnitPrice int
					sort.Ints(v[k2])
					if len(v[k2])%2 == 0 {
						midUnitPrice = v[k2][len(v[k2])/2-1]
					} else {
						midUnitPrice = v[k2][len(v[k2])/2]
					}
					for _, vv := range v[k2] {
						avgUnitPrice += vv
					}
					skuNameMap[k2] = &model.PriceReferSnapshot{
						MidUnitPrice: midUnitPrice,
						MaxUnitPrice: v[k2][len(v[k2])-1],
						MinUnitPrice: v[k2][0],
						AvgUnitPrice: avgUnitPrice / len(v[k2]),
					}
				}
				resultMap[k1] = skuNameMap
			}
			if len(priceReferSnapshotList) > 0 {
				for _, v := range priceReferSnapshotList {
					if v.CityCode == 0 {
						if resultCountryMap[v.NameID] != nil {
							v.MidUnitPrice = resultCountryMap[v.NameID].MidUnitPrice
							v.MaxUnitPrice = resultCountryMap[v.NameID].MaxUnitPrice
							v.AvgUnitPrice = resultCountryMap[v.NameID].AvgUnitPrice
							v.MinUnitPrice = resultCountryMap[v.NameID].MinUnitPrice
							dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
						}
						continue
					}
					if resultMap[v.CityCode][v.NameID] != nil {
						v.MidUnitPrice = resultMap[v.CityCode][v.NameID].MidUnitPrice
						v.MaxUnitPrice = resultMap[v.CityCode][v.NameID].MaxUnitPrice
						v.AvgUnitPrice = resultMap[v.CityCode][v.NameID].AvgUnitPrice
						v.MinUnitPrice = resultMap[v.CityCode][v.NameID].MinUnitPrice
						dao.UpdateEntity(db, v, "MidUnitPrice", "MaxUnitPrice", "MinUnitPrice", "AvgUnitPrice")
					}
				}
			}
		case 2:
			if len(priceReferSnapshotList) > 0 {
				for _, v := range priceReferSnapshotList {
					result, _ := dao.GetPriceReferPrice(db, v.CityCode, v.SkuID, snapshotAt)
					if result != nil {
						v.MaxPrice = result.MaxPrice
						v.MinPrice = result.MinPrice
						v.AvgPrice = result.AvgPrice
						v.MidPrice = result.MidPrice
						dao.UpdateEntity(db, v, "MidPrice", "MaxPrice", "MinPrice", "AvgPrice")
					}
				}
			}
			//TODO 京东查询接口报错，暂时屏蔽了
			// case 3:
			// priceReferSnapshotList, err = dao.GetPriceReferSnapshotNoPage(db, []int{0}, nil, nil, snapshotAt)
			// taskFunc := func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
			// 	v := batchItemList[0].(*model.PriceReferSnapshot)
			// 	for _, appOrg := range apimanager.CurAPIManager.GetAppOrgCodeList(model.VendorIDJD) {
			// 		directPrice, _ := jd.GetAPI(appOrg).GetJdSkuDirectPrice(v.SkuID)
			// 		v.JdDirectPrice = int(directPrice)
			// 		dao.UpdateEntity(db, v, "JdDirectPrice")
			// 	}
			// 	return retVal, err
			// }
			// taskParallel := tasksch.NewParallelTask("获取并更新京东指导价格", tasksch.NewParallelConfig(), ctx, taskFunc, priceReferSnapshotList)
			// tasksch.HandleTask(taskParallel, task, true).Run()
			// _, err = taskParallel.GetResult(0)
		}
		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
}

type GetManageStateResult struct {
	OpenStoreCount     int                      `json:"openStoreCount"`     //营业店铺数
	HaveRestStoreCount int                      `json:"haveRestStoreCount"` //临时休息店铺数
	RestStoreCount     int                      `json:"restStoreCount"`     //休息店铺数
	FinishOrderState   *GetManageStateOrderInfo //完成订单情况
	IngOrderState      *GetManageStateOrderInfo //进行中订单情况
	CancelOrderState   *GetManageStateOrderInfo //取消订单情况
}

type GetManageStateOrderInfo struct {
	ActualPayPrice int    `json:"actualPayPrice"` //支付总额
	TotalShopMoney int    `json:"totalShopMoney"` //平台结算
	DesiredFee     int    `json:"desiredFee"`     //配送费
	Yhld           string `json:"yhld"`           //优惠力度（支付总额-平台结算-配送支出）/支付总额*100%
}

func getStoreStatusCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (count int, err error) {
	countType := &struct{ Count int }{}
	sqlParams := []interface{}{}
	sql := `
		SELECT COUNT(DISTINCT a.id) count
		  FROM store a
	 LEFT JOIN store_map b ON a.id = b.store_id AND b.deleted_at = ?
		 WHERE a.deleted_at = ? 
	`
	sqlParams = append(sqlParams, utils.DefaultTimeValue, utils.DefaultTimeValue)
	if len(cityCodes) > 0 {
		sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
		sqlParams = append(sqlParams, cityCodes)
	}
	if vendorID != -1 {
		sql += " AND b.vendor_id = ? AND b.status = ?"
		sqlParams = append(sqlParams, vendorID, status)
	} else {
		sql += " AND a.status = ?"
		sqlParams = append(sqlParams, status)
	}
	err = dao.GetRow(db, &countType, sql, sqlParams)
	return countType.Count, err
}

func getOrderStateCount(db *dao.DaoDB, cityCodes []int, vendorID, status int) (getManageStateOrderInfo *GetManageStateOrderInfo, err error) {
	sqlParams := []interface{}{}
	getManageStateOrderInfo = &GetManageStateOrderInfo{}
	endTime := time.Now().AddDate(0, -3, 0)
	sql := `
		SELECT SUM(b.actual_pay_price) actual_pay_price, SUM(b.total_shop_money) total_shop_money, SUM(IFNULL(c.desired_fee, 0)) desired_fee
		  FROM store a
	 LEFT JOIN goods_order b ON a.id = IF(b.jx_store_id = 0, b.store_id, b.jx_store_id)
	 LEFT JOIN waybill c ON IF(b.waybill_vendor_id = -1,b.vendor_order_id,b.vendor_waybill_id) = c.vendor_waybill_id
		 WHERE a.deleted_at = ? AND a.status <> ?
		   AND b.order_created_at < ? AND b.order_created_at > ?
	`
	sqlParams = append(sqlParams, utils.DefaultTimeValue, model.StoreStatusDisabled, time.Now(), endTime)
	if len(cityCodes) > 0 {
		sql += " AND a.city_code IN (" + dao.GenQuestionMarks(len(cityCodes)) + ")"
		sqlParams = append(sqlParams, cityCodes)
	}
	if vendorID != -1 {
		sql += " AND b.vendor_id = ?"
		sqlParams = append(sqlParams, vendorID)
	}
	if status != model.OrderStatusDelivering {
		sql += " AND b.status = ?"
		sqlParams = append(sqlParams, status)
	} else {
		sql += " AND b.status < ? AND b.status >= ?"
		sqlParams = append(sqlParams, model.OrderStatusEndBegin, model.OrderStatusWait4Pay)
	}
	err = dao.GetRow(db, &getManageStateOrderInfo, sql, sqlParams)
	getManageStateOrderInfo.Yhld = utils.Float64ToStr(math.Round((float64(getManageStateOrderInfo.ActualPayPrice-getManageStateOrderInfo.TotalShopMoney-getManageStateOrderInfo.DesiredFee) / float64(getManageStateOrderInfo.ActualPayPrice) * 100))) + "%"
	return getManageStateOrderInfo, err
}

func GetManageState(ctx *jxcontext.Context, cityCodes []int, vendorID int) (getManageStateResult *GetManageStateResult, err error) {
	var (
		db = dao.GetDB()
	)
	getManageStateResult = &GetManageStateResult{}
	if openCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusOpened); err == nil {
		getManageStateResult.OpenStoreCount = openCount
	}
	if haveRestCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusHaveRest); err == nil {
		getManageStateResult.HaveRestStoreCount = haveRestCount
	}
	if restCount, err := getStoreStatusCount(db, cityCodes, vendorID, model.StoreStatusClosed); err == nil {
		getManageStateResult.RestStoreCount = restCount
	}
	if finishCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusFinished); err == nil {
		getManageStateResult.FinishOrderState = finishCount
	}
	if ingCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusDelivering); err == nil {
		getManageStateResult.IngOrderState = ingCount
	}
	if cancelCount, err := getOrderStateCount(db, cityCodes, vendorID, model.OrderStatusCanceled); err == nil {
		getManageStateResult.CancelOrderState = cancelCount
	}
	return getManageStateResult, err
}

func RefreshStoreManageState(ctx *jxcontext.Context, storeIDs []int, vendorIDs []int) {
	var (
		db = dao.GetDB()
		//vendorIDs   = []int{model.VendorIDJD, model.VendorIDMTWM, model.VendorIDEBAI}
		messageFlag = time.Now().Hour() == 10 && time.Now().Minute() > 0 && time.Now().Minute() < 12
	)
	task := tasksch.NewParallelTask("RefreshStoreManageState", tasksch.NewParallelConfig().SetParallelCount(3).SetIsContinueWhenError(true), ctx,
		func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
			vendorID := batchItemList[0].(int)
			storeMaps, err := dao.GetStoresMapList(db, []int{vendorID}, storeIDs, []int{model.StoreStatusOpened, model.StoreStatusClosed, model.StoreStatusHaveRest}, model.StoreStatusAll, model.StoreIsSyncAll, "", "", "")
			storeManageStates, err := dao.GetStoreManageStateSimple(db, storeIDs, nil, vendorID)
			var (
				storeMapsMap           = make(map[int]*model.StoreMap)
				storeManagesMap        = make(map[int]*model.StoreManageState)
				deleteList             []int
				createList, updateList []*model.StoreMap
			)
			for _, v := range storeMaps {
				storeMapsMap[v.StoreID] = v
			}
			for _, v := range storeManageStates {
				storeManagesMap[v.StoreID] = v
				if storeMapsMap[v.StoreID] != nil {
					updateList = append(updateList, storeMapsMap[v.StoreID])
				} else {
					deleteList = append(deleteList, v.StoreID)
				}
			}
			for _, v := range storeMapsMap {
				if storeManagesMap[v.StoreID] == nil {
					createList = append(createList, v)
				}
			}
			task2 := tasksch.NewParallelTask("deleteList", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
				func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
					storeID := batchItemList[0].(int)
					storeManage := &model.StoreManageState{
						StoreID:  storeID,
						VendorID: vendorID,
					}
					dao.DeleteEntity(db, storeManage, "StoreID", "VendorID")
					return retVal, err
				}, deleteList)
			tasksch.HandleTask(task2, task, true).Run()
			task2.GetResult(0)
			task3 := tasksch.NewParallelTask("createList", tasksch.NewParallelConfig().SetParallelCount(20).SetIsContinueWhenError(true), ctx,
				func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
					storeMap := batchItemList[0].(*model.StoreMap)
					if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
						return retVal, err
					}
					storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
					if storeDetail == nil {
						return retVal, err
					}
					storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
					if storeManage == nil {
						return retVal, err
					}
					dao.CreateEntity(db, storeManage)
					return retVal, err
				}, createList)
			tasksch.HandleTask(task3, task, true).Run()
			task3.GetResult(0)
			task4 := tasksch.NewParallelTask("updateList", tasksch.NewParallelConfig().SetParallelCount(1).SetIsContinueWhenError(true), ctx,
				func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
					storeMap := batchItemList[0].(*model.StoreMap)
					if storeMap.VendorOrgCode == "" || storeMap.VendorStoreID == "" {
						return retVal, err
					}
					storeDetail, _ := dao.GetStoreDetail(db, storeMap.StoreID, vendorID, storeMap.VendorOrgCode)
					if storeDetail == nil {
						return retVal, err
					}
					storeManage := buildStoreManageState(ctx, db, storeMap, storeDetail, messageFlag)
					if storeManage == nil {
						return retVal, err
					}
					if storeManageStates, err := dao.GetStoreManageStateSimple(db, []int{storeDetail.ID}, nil, vendorID); err == nil && len(storeManageStates) > 0 {
						storeManage.ID = storeManageStates[0].ID
						dao.UpdateEntity(db, storeManage)
					}
					return retVal, err
				}, updateList)
			tasksch.HandleTask(task4, task, true).Run()
			task4.GetResult(0)
			return retVal, err
		}, vendorIDs)
	tasksch.HandleTask(task, nil, true).Run()
	task.GetID()
}

func buildStoreManageState(ctx *jxcontext.Context, db *dao.DaoDB, storeMap *model.StoreMap, storeDetail *dao.StoreDetail, messageFlag bool) *model.StoreManageState {
	var (
		dayTimeBegin, dayTimeEnd = utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "00:00:00"), utils.Str2Time(utils.Time2Str(utils.Time2Date(time.Now())) + "23:59:59")
	)
	storeManage := &model.StoreManageState{
		StoreID:  storeMap.StoreID,
		VendorID: storeMap.VendorID,
	}
	dao.WrapAddIDCULEntity(storeManage, ctx.GetUserName())
	handler := partner.GetPurchasePlatformFromVendorID(storeMap.VendorID)
	store, err := handler.ReadStore(ctx, storeDetail.VendorOrgCode, storeDetail.VendorStoreID, storeDetail.VendorStoreName)
	if err != nil || store == nil {
		return nil
	}
	// if coverAreaFlag {
	if storeMap.VendorID == model.VendorIDJD && store.DeliveryRangeType != model.DeliveryRangeTypePolygon {
		storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", math.Pi*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)*utils.Str2Float64WithDefault(store.DeliveryRange, 0)/float64(1000)))
	} else {
		storeManage.CoverArea = utils.Str2Float64(fmt.Sprintf("%.2f", CalculateCoverArea(strings.Split(store.DeliveryRange, ";"), storeMap.VendorID)))
	}
	// }
	//营业状态
	storeManage.VendorStatus = store.Status
	//不一致发消息
	//if messageFlag {
	//	vendorStatus, status := -1, -1
	//	if store.Status == model.StoreStatusOpened {
	//		vendorStatus = 1
	//	}
	//	if storeDetail.Status == model.StoreStatusOpened {
	//		status = 1
	//	}
	//	//statusMap := map[int]string{
	//	//	1:  "营业",
	//	//	-1: "休息",
	//	//}
	//	//if vendorStatus != status {
	//	//	content := "您的门店 [" + storeDetail.Name + "]，ID:[" + utils.Int2Str(storeDetail.ID) + "]，在[" + model.VendorChineseNames[storeMap.VendorID] + "] 平台上营业状态和京西不一致！平台状态：【" + statusMap[vendorStatus] + "】，京西状态：【" + statusMap[status] + "】"
	//	//	if user, err := dao.GetUserByID(db, "mobile", storeDetail.MarketManPhone); err == nil {
	//	//		ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.UserID, "平台门店状态变化", content)
	//	//	}
	//	//}
	//}
	//营业时长
	optime := jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime1, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime1, time.Now())).Hours()
	if storeDetail.CloseTime2 != 0 && storeDetail.OpenTime2 != 0 {
		optime += jxutils.JxOperationTime2TimeByDate(storeDetail.CloseTime2, time.Now()).Sub(jxutils.JxOperationTime2TimeByDate(storeDetail.OpenTime2, time.Now())).Hours()
	}
	storeManage.OpenTime = utils.Str2Float64(fmt.Sprintf("%.2f", optime))
	//商品数
	highSkuCount := 0
	storeSkus, _ := dao.GetStoresSkusForManageState(db, storeMap.StoreID, model.StoreSkuBindStatusNormal)
	for _, v := range storeSkus {
		if v.UnitPrice > v.MidUnitPrice {
			highSkuCount++
		}
	}
	storeManage.SkuCount, storeManage.HighSkuCount = len(storeSkus), highSkuCount
	//活动丰富度
	ample, _ := handler.GetActAmple(ctx, storeDetail.VendorStoreID, storeDetail.VendorStoreID)
	storeManage.ActAmple = ample
	//订单
	refuseOrderCount := 0
	orderList, _ := dao.QueryOrdersForManageState(db, storeMap.StoreID, storeMap.VendorID, model.OrderStatusCanceled, dayTimeBegin, dayTimeEnd)
	for _, v := range orderList {
		if v.BindID == 0 {
			refuseOrderCount++
		}
	}
	storeManage.NullOrderCount, storeManage.RefuseOrderCount = len(orderList), refuseOrderCount
	//评分（美团）
	if storeMap.VendorID == model.VendorIDMTWM {
		mtapi := partner.CurAPIManager.GetAPI(model.VendorIDMTWM, storeDetail.VendorOrgCode).(*mtwmapi.API)
		if scoreResult, err := mtapi.CommentScore(storeDetail.VendorStoreID); err == nil {
			storeManage.StoreScore = scoreResult.AvgPoiScore
		}
	}
	return storeManage
}

func GetStoreManageState(ctx *jxcontext.Context, storeIDs, brandIDs []int, vendorID, sortType, offset, pageSize int) (pageInfo *model.PagedInfo, err error) {
	var (
		db = dao.GetDB()
	)
	//权限
	if permission.IsRoled(ctx) {
		if storeIDsMap, err := permission.GetUserStoresResultMap(ctx.GetUserID()); err == nil {
			var storeIDs2 []int
			if len(storeIDs) > 0 {
				for _, v := range storeIDs {
					if storeIDsMap[v] != 0 {
						storeIDs2 = append(storeIDs2, v)
					}
				}
				if len(storeIDs2) == 0 {
					storeIDs2 = append(storeIDs2, -1)
				}
			} else {
				for k, _ := range storeIDsMap {
					storeIDs2 = append(storeIDs2, k)
				}
			}
			storeIDs = nil
			storeIDs = storeIDs2
		}
	}
	return dao.GetStoreManageState(db, storeIDs, brandIDs, vendorID, sortType, offset, pageSize)
}

func CalculateCoverArea(coordinate []string, vendorID int) (area float64) {
	//我先把地理坐标转成了平面坐标（百度的方法）
	//然后按多个坐标求面积公式求的面积（百度的方法）
	if len(coordinate) == 0 {
		return 0
	}
	var xyList [][2]float64
	for _, v := range coordinate {
		cell := strings.Split(v, ",")
		if len(cell) == 0 || len(cell) == 1 {
			continue
		}
		var lat, lng float64
		if vendorID == model.VendorIDJD || vendorID == model.VendorIDEBAI {
			lng = utils.Str2Float64WithDefault(cell[0], 0)
			lat = utils.Str2Float64WithDefault(cell[1], 0)
		} else {
			lat = utils.Str2Float64WithDefault(cell[0], 0)
			lng = utils.Str2Float64WithDefault(cell[1], 0)
		}
		xys := jxutils.MillierConvertion(lat, lng)
		xyList = append(xyList, xys)
	}
	var sum float64 = 0
	if len(xyList) == 0 {
		return 0
	}
	for i := 0; i < len(xyList)-1; i++ {
		// sum += (xyList[i+1][0] - xyList[i][0]) * (xyList[i+1][1] + xyList[i][1])
		sum += (xyList[i][0]*xyList[i+1][1] - xyList[i+1][0]*xyList[i][1])
	}
	// sum += (xyList[0][0] - xyList[len(xyList)-1][0]) * (xyList[0][1] + xyList[len(xyList)-1][1])
	sum += (xyList[len(xyList)-1][0]*xyList[0][1] - xyList[0][0]*xyList[len(xyList)-1][1])
	sum /= float64(2)
	sum = math.Abs(sum)
	sum = utils.Str2Float64(fmt.Sprintf("%.2f", sum))
	return sum
}

func RefreshJDMembers(ctx *jxcontext.Context) (err error) {
	var (
		db        = dao.GetDB()
		pageSize  = 50
		page      int
		pages     []int
		memberMap = make(map[string]*model.UserMember)
	)
	userMemebers, _ := dao.GetUserMemberWithoutDeleted(db, model.VendorIDJD)
	for _, v := range userMemebers {
		memberMap[v.Mobile] = v
	}
	pageResult, err := api.JdAPI.QueryMemberTransListByCondition("", "", page, pageSize)
	if err != nil {
		if strings.Contains(err.Error(), "cookie") {
			globals.SugarLogger.Warnf("京东cookie过期了!")
		}
	}
	if pageResult.Total%pageSize == 0 {
		page = pageResult.Total / pageSize
	} else {
		page = pageResult.Total/pageSize + 1
	}
	for ; page > 0; page-- {
		pages = append(pages, page)
	}
	task := tasksch.NewParallelTask2("RefreshJDMembers", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
		func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, successCount int, err error) {
			pageNo := batchItemList[0].(int)
			pageResult2, err := api.JdAPI.QueryMemberTransListByCondition("", "", pageNo, pageSize)
			if pageResult2 != nil {
				for _, v := range pageResult2.Rows {
					if utils.Str2Time(v.Endtimestr+" 23:59:59").Sub(time.Now()) >= 0 && v.Dealstatus == 0 {
						if memberMap[v.Merchantcardno] != nil { //库里有这个人的会员信息了
							if utils.Time2Str(memberMap[v.Merchantcardno].EndAt) != v.Endtimestr+" 23:59:59" { //可能这个人续费了，续存了
								memberMap[v.Merchantcardno].EndAt = utils.Str2Time(v.Endtimestr + " 23:59:59")
								memberMap[v.Merchantcardno].DeletedAt = utils.DefaultTimeValue
								dao.UpdateEntity(db, memberMap[v.Merchantcardno], "EndAt", "DeletedAt")
							}
						} else {
							userMember := &model.UserMember{
								VendorOrderID: v.Orderid,
								VendorID:      model.VendorIDJD,
								Mobile:        v.Merchantcardno,
								MemberType:    1,
								EndAt:         utils.Str2Time(v.Endtimestr + " 23:59:59"),
								IsPay:         1,
							}
							dao.WrapAddIDCULDEntity(userMember, "jxadmin")
							if v.Createtime != "" {
								userMember.CreatedAt = utils.Str2Time(v.Createtime)
							} else {
								userMember.CreatedAt = utils.Str2Time(v.Cardcreatetime)
							}
							if userMember.EndAt.Sub(time.Now()) <= 0 {
								userMember.DeletedAt = time.Now()
							}
							dao.CreateEntity(db, userMember)
						}
					}
				}
			}
			return retVal, successCount, err
		}, pages)
	tasksch.HandleTask(task, nil, true).Run()
	task.GetID()
	return err
}

func UserMemberReport(ctx *jxcontext.Context, vendorID int, keyword string, offset, pageSize int) (page *model.PagedInfo, err error) {
	var (
		db = dao.GetDB()
	)
	var list []*dao.UserMemberReportResult
	sql := `
		SELECT SQL_CALC_FOUND_ROWS a.mobile, IF(a.vendor_id = ?, b.name, t1.consignee_name) name, IF(a.deleted_at = ?, ?, ?) status, a.vendor_id, t1.buy_count, t1.buy_price,
			t1.good_comment_count, t1.bad_comment_count, t2.finished_count, t2.finished_price
		FROM user_member a
		LEFT JOIN user b ON a.mobile = b.mobile 
		LEFT JOIN (
			SELECT a.mobile, MAX(b.consignee_name) consignee_name, COUNT(b.vendor_store_id) buy_count, SUM(b.actual_pay_price) buy_price, COUNT(c.score > 3) good_comment_count, COUNT(c.score < 3) bad_comment_count 
			FROM user_member a
			LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND b.store_id <> ?
			LEFT JOIN jx_bad_comments c ON c.order_id = b.vendor_order_id
			GROUP BY 1
		) t1 ON t1.mobile = a.mobile 
		LEFT JOIN (
			SELECT a.mobile, COUNT(b.vendor_store_id) finished_count, SUM(b.actual_pay_price) finished_price
			FROM user_member a
			LEFT JOIN goods_order b ON a.mobile = b.consignee_mobile2 AND a.vendor_id = b.vendor_id AND b.order_type = ? AND status = ? AND b.store_id <> ?
			GROUP BY 1
		)t2 ON t2.mobile = a.mobile
		WHERE 1 = 1
	`
	sqlParams := []interface{}{
		model.VendorIDJX, utils.DefaultTimeValue, model.YES, model.NO,
		model.OrderTypeNormal, model.MatterStoreID,
		model.OrderTypeNormal, model.OrderStatusFinished, model.MatterStoreID,
	}
	if vendorID != -1 {
		sql += " AND a.vendor_id = ?"
		sqlParams = append(sqlParams, vendorID)
	}
	if keyword != "" {
		keywordLike := "%" + keyword + "%"
		sql += " AND (a.mobile LIKE ? OR name LIKE ?)"
		sqlParams = append(sqlParams, keywordLike, keywordLike)
	}
	sql += `
		LIMIT ? OFFSET ?
	`
	pageSize = jxutils.FormalizePageSize(pageSize)
	sqlParams = append(sqlParams, pageSize, offset)
	txDB, _ := dao.Begin(db)
	defer dao.Commit(db, txDB)
	if err = dao.GetRowsTx(txDB, &list, sql, sqlParams...); err == nil {
		page = &model.PagedInfo{
			TotalCount: dao.GetLastTotalRowCount2(db, txDB),
			//Data:       page,
		}
		task := tasksch.NewParallelTask("", tasksch.NewParallelConfig().SetIsContinueWhenError(true), jxcontext.AdminCtx,
			func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
				v := batchItemList[0].(*dao.UserMemberReportResult)
				var good *model.GoodsOrder
				sql := `
					SELECT * FROM goods_order WHERE consignee_mobile2 = ? AND vendor_id = ? AND order_type = ? AND store_id <> ? LIMIT 1 OFFSET 0
				`
				sqlParams := []interface{}{v.Mobile, v.VendorID, model.OrderTypeNormal, model.MatterStoreID}
				dao.GetRow(db, &good, sql, sqlParams)
				if good != nil {
					v.NewPrice = good.ActualPayPrice
				}
				var place *model.Place
				sql2 := `
					SELECT a.* FROM place a,(
					SELECT b.city_code, COUNT(*) count
				     FROM goods_order a
				LEFT JOIN store b ON b.id = IF(a.jx_store_id = 0, store_id, jx_store_id)
				    WHERE consignee_mobile2 = ? AND vendor_id = ?
				 GROUP BY 1
				 ORDER BY COUNT(*)
					LIMIT 1 OFFSET 0)b
					WHERE a.code = b.city_code
				`
				dao.GetRow(db, &place, sql2, sqlParams)
				if place != nil {
					v.CityName = place.Name
					v.CityCode = place.Code
				}
				return retVal, err
			}, list)
		tasksch.HandleTask(task, nil, true).Run()
		task.GetResult(0)
		page.Data = list
	}
	return page, err
}

type OrderNotifyReportResult struct {
	StoreID    int    `orm:"column(store_id)" json:"storeID"`
	Name       string `json:"name"`
	Count      int    `json:"count"`      //总通知数
	SmsCount   int    `json:"smsCount"`   //短信通知数
	VoiceCount int    `json:"voiceCount"` //语音通知数
}

func OrderNotifyReport(ctx *jxcontext.Context, storeIDs, brandIDs []int, vendorID, notifyType int, keyword string, isFinished bool, fromTime, toTime string, offset, pageSize int) (page *model.PagedInfo, err error) {
	var (
		db      = dao.GetDB()
		results []*OrderNotifyReportResult
	)
	sql := `
		SELECT SQL_CALC_FOUND_ROWS IF(a.store_id = 0, a.jx_store_id, a.store_id) store_id, b.name ,COUNT(*) count, COUNT(a.notify_type = 1 or NULL) sms_count, COUNT(a.notify_type = 2 or NULL) voice_count
		  FROM goods_order a
	 LEFT JOIN store b ON IF(a.store_id = 0 ,a.jx_store_id, a.store_id) = b.id
	 LEFT JOIN user c ON c.mobile = b.market_man_phone
	 LEFT JOIN user d ON d.mobile = b.operator_phone
		 WHERE a.notify_type <> ?	
`
	sqlParams := []interface{}{0}
	if len(storeIDs) > 0 {
		sql += ` AND IF(a.jx_store_id != 0, a.jx_store_id, a.store_id) IN(` + dao.GenQuestionMarks(len(storeIDs)) + `)`
		sqlParams = append(sqlParams, storeIDs)
	}
	if len(brandIDs) > 0 {
		sql += ` AND b.brand_id IN(` + dao.GenQuestionMarks(len(brandIDs)) + `)`
		sqlParams = append(sqlParams, brandIDs)
	}
	if vendorID != -1 {
		sql += " AND a.vendor_id = ?"
		sqlParams = append(sqlParams, vendorID)
	}
	if notifyType != -1 {
		sql += " AND a.notify_type = ?"
		sqlParams = append(sqlParams, notifyType)
	}
	if keyword != "" {
		sql += " AND (b.name LIKE ? OR c.name LIKE ? OR d.name LIKE ? OR b.id = ? OR a.vendor_order_id = ?)"
		sqlParams = append(sqlParams, "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%", keyword, keyword)
	}
	if !utils.IsTimeZero(utils.Str2Time(fromTime)) {
		if isFinished {
			sql += " AND a.order_finished_at > ?"
		} else {
			sql += " AND a.order_created_at > ?"
		}
		sqlParams = append(sqlParams, fromTime)
	}
	if !utils.IsTimeZero(utils.Str2Time(toTime)) {
		if isFinished {
			sql += " AND a.order_finished_at < ?"
		} else {
			sql += " AND a.order_created_at < ?"
		}
		sqlParams = append(sqlParams, toTime)
	}
	sql += `
		GROUP BY 1, 2
		ORDER BY count DESC
		LIMIT ? OFFSET ?
	`
	pageSize = jxutils.FormalizePageSize(pageSize)
	sqlParams = append(sqlParams, pageSize, offset)
	txDB, _ := dao.Begin(db)
	defer dao.Commit(db, txDB)
	if err = dao.GetRowsTx(txDB, &results, sql, sqlParams...); err == nil {
		page = &model.PagedInfo{
			TotalCount: dao.GetLastTotalRowCount2(db, txDB),
			Data:       results,
		}
	}
	return page, err
}

type OrderDeliveryReportResult struct {
	model.GoodsOrder
	DesiredFee int `json:"desiredFee"`
}

func OrderDeliveryReport(ctx *jxcontext.Context, storeIDs, brandIDs []int, vendorID, deliveryVendorID int, keyword string, isFinished bool, fromTime, toTime string, offset, pageSize int) (page *model.PagedInfo, err error) {
	var (
		db      = dao.GetDB()
		results []*OrderDeliveryReportResult
	)
	sql := `
		SELECT SQL_CALC_FOUND_ROWS a.*, b.desired_fee
		  FROM goods_order a
	 LEFT JOIN waybill b ON a.vendor_order_id = b.vendor_order_id AND a.waybill_vendor_id = b.waybill_vendor_id
	 LEFT JOIN store c ON c.id = IF(a.jx_store_id = 0, a.store_id, a.jx_store_id)
		 WHERE b.status <> ? AND a.waybill_vendor_id IN (? , ? , ?)
`
	sqlParams := []interface{}{model.WaybillStatusCanceled, model.VendorIDMTPS, model.VendorIDDada, model.VendorIDFengNiao, model.VendorIDUUPT}
	if len(storeIDs) > 0 {
		sql += ` AND IF(a.jx_store_id != 0, a.jx_store_id, a.store_id) IN(` + dao.GenQuestionMarks(len(storeIDs)) + `)`
		sqlParams = append(sqlParams, storeIDs)
	}
	if len(brandIDs) > 0 {
		sql += ` AND c.brand_id IN(` + dao.GenQuestionMarks(len(brandIDs)) + `)`
		sqlParams = append(sqlParams, brandIDs)
	}
	if vendorID != -1 {
		sql += " AND a.vendor_id = ?"
		sqlParams = append(sqlParams, vendorID)
	}
	if deliveryVendorID != -1 {
		sql += " AND a.waybill_vendor_id = ?"
		sqlParams = append(sqlParams, deliveryVendorID)
	}
	if keyword != "" {
		sql += " AND (c.name LIKE ? OR c.id = ? OR a.vendor_order_id = ?)"
		sqlParams = append(sqlParams, "%"+keyword+"%", keyword, keyword)
	}
	if !utils.IsTimeZero(utils.Str2Time(fromTime)) {
		if isFinished {
			sql += " AND a.order_finished_at > ?"
		} else {
			sql += " AND a.order_created_at > ?"
		}
		sqlParams = append(sqlParams, fromTime)
	}
	if !utils.IsTimeZero(utils.Str2Time(toTime)) {
		if isFinished {
			sql += " AND a.order_finished_at < ?"
		} else {
			sql += " AND a.order_created_at < ?"
		}
		sqlParams = append(sqlParams, toTime)
	}
	sql += `
		ORDER BY a.order_created_at DESC
		LIMIT ? OFFSET ?
	`
	pageSize = jxutils.FormalizePageSize(pageSize)
	sqlParams = append(sqlParams, pageSize, offset)
	txDB, _ := dao.Begin(db)
	defer dao.Commit(db, txDB)
	if err = dao.GetRowsTx(txDB, &results, sql, sqlParams...); err == nil {
		page = &model.PagedInfo{
			TotalCount: dao.GetLastTotalRowCount2(db, txDB),
			Data:       results,
		}
	}
	return page, err
}
