package common

import (
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/tencent_map"
	"sort"

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

type Store4User struct {
	model.ModelIDCULD

	OriginalName      string `orm:"-" json:"originalName"`
	Name              string `orm:"size(255)" json:"name"`
	OpenTime1         int16  `json:"openTime1"`  // 930就表示9点半，用两个的原因是为了支持中午休息，1与2的时间段不能交叉，为0表示没有
	CloseTime1        int16  `json:"closeTime1"` // 格式同上
	OpenTime2         int16  `json:"openTime2"`  // 格式同上
	CloseTime2        int16  `json:"closeTime2"` // 格式同上
	Status            int    `json:"status"`
	CityCode          int    `orm:"default(0);null" json:"cityCode"`     // todo ?
	DistrictCode      int    `orm:"default(0);null" json:"districtCode"` // todo ?
	Address           string `orm:"size(255)" json:"address"`
	Tel1              string `orm:"size(32);index" json:"tel1"`
	Tel2              string `orm:"size(32);index" json:"tel2"`
	Lng               int    `json:"-"`                  // 乘了10的6次方
	Lat               int    `json:"-"`                  // 乘了10的6次方
	DeliveryRangeType int8   `json:"-"`                  // 参见相关常量定义
	DeliveryRange     string `orm:"type(text)" json:"-"` // 如果DeliveryRangeType为DeliveryRangeTypePolygon，则为逗号分隔坐标，分号分隔的坐标点（坐标与Lng和Lat一样，都是整数），比如 121361504,31189308;121420555,31150238。否则为半径，单位为米

	FloatLng     float64 `json:"lng"`
	FloatLat     float64 `json:"lat"`
	CityName     string  `json:"cityName"`
	DistrictName string  `json:"districtName"`

	Distance     int `json:"distance"`
	WalkDistance int `json:"walkDistance"`
	DeliverySelf int `json:"deliverySelf"`
}

type Store4UserList []*Store4User

func (x Store4UserList) Len() int {
	return len(x)
}

func (x Store4UserList) Less(i, j int) bool {
	if x[i].Status != x[j].Status {
		return x[i].Status > x[j].Status
	}
	if x[i].WalkDistance != x[j].WalkDistance {
		return x[i].WalkDistance < x[j].WalkDistance
	}
	return x[i].Distance < x[j].Distance
}

func (x Store4UserList) Swap(i, j int) {
	x[i], x[j] = x[j], x[i]
}

func GetNearSupplyGoodsStoreByStoreID(ctx *jxcontext.Context, storeID int) (store *model.Store, err error) {
	var (
		stores []*model.Store
		db     = dao.GetDB()
	)
	store2, _ := dao.GetStoreDetail(db, storeID, model.VendorIDJX, "")
	if store2 == nil {
		return nil, fmt.Errorf("该门店未绑定京西平台！storeID: %v", storeID)
	}
	if store2.IsSupplyGoods == model.YES {
		return nil, fmt.Errorf("该门店已经是货源门店，无法从其他货源门店进货！storeID: %v", storeID)
	}
	sql := `
		SELECT a.* 
		  FROM store a
		  JOIN store_map b ON b.store_id = a.id 
		  JOIN store c ON c.city_code = a.city_code AND c.id = ?
		 WHERE a.deleted_at = ? 
		   AND b.deleted_at = ? 
		   AND b.vendor_id = ?
		   AND b.is_supply_goods = ?
		   AND a.status = ?   
	`
	sqlParams := []interface{}{
		storeID,
		utils.DefaultTimeValue, utils.DefaultTimeValue,
		model.VendorIDJX, model.YES, model.StoreStatusOpened,
	}
	err = dao.GetRows(db, &stores, sql, sqlParams...)
	if len(stores) > 0 {
		realDistance := float64(0)
		for _, v := range stores {
			distance := jxutils.EarthDistance(jxutils.IntCoordinate2Standard(v.Lng), jxutils.IntCoordinate2Standard(v.Lat), jxutils.IntCoordinate2Standard(store2.Lng), jxutils.IntCoordinate2Standard(store2.Lat))
			if realDistance == 0 {
				realDistance = distance
				store = v
			} else {
				if realDistance > distance {
					realDistance = distance
					store = v
				}
			}
		}
	}
	return store, err
}

func GetStoreListByLocation(ctx *jxcontext.Context, lng, lat float64, maxRadius int, needWalkDistance, isJds bool, brandID []int) (storeList []*Store4User, err error) {
	const (
		maxStoreCount4User = 5
	)

	var (
		sql       string
		sqlParams []interface{}
	)

	lng2, _ := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 90)
	_, lat2 := jxutils.ConvertDistanceToLogLat(lng, lat, float64(maxRadius), 0)
	lng1 := lng - (lng2 - lng)
	lat1 := lat - (lat2 - lat)
	if !isJds {
		sql = `
		SELECT t1.*,
		city.name city_name,sm.delivery_self 
		FROM store t1
		JOIN place city ON city.code = t1.city_code
		JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status <> ?
		WHERE t1.deleted_at = ? AND t1.status <> ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
		AND sm.is_order <> ?
		AND t1.id <> ?
		`
		sqlParams = append(sqlParams,
			model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
			utils.DefaultTimeValue, model.StoreStatusDisabled, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
			model.YES,
			model.MatterStoreID,
		)
		if len(brandID) != 0 {
			sql += " AND t1.brand_id IN  (" + dao.GenQuestionMarks(len(brandID)) + ")"
			sqlParams = append(sqlParams, brandID)
		}
		sql += `
		ORDER BY t1.id
		`
	} else {
		sql = `
		SELECT t1.*,
		city.name city_name,sm.delivery_self 
		FROM store t1
		JOIN place city ON city.code = t1.city_code
		JOIN store_map sm ON sm.store_id = t1.id AND sm.vendor_id = ? AND sm.deleted_at = ? AND sm.status = ?
		WHERE t1.deleted_at = ? AND t1.status = ? AND t1.lng > ? AND t1.lng < ? AND t1.lat > ? AND t1.lat < ?
		AND sm.is_order <> ?
		AND t1.id <> ?
		ORDER BY t1.id
		`
		sqlParams = []interface{}{
			model.VendorIDJDShop, utils.DefaultTimeValue, model.StoreStatusOpened,
			utils.DefaultTimeValue, model.StoreStatusOpened, jxutils.StandardCoordinate2Int(lng1), jxutils.StandardCoordinate2Int(lng2), jxutils.StandardCoordinate2Int(lat1), jxutils.StandardCoordinate2Int(lat2),
			model.YES,
			model.MatterStoreID,
		}
	}
	var storeList1 []*Store4User
	if err = dao.GetRows(dao.GetDB(), &storeList1, sql, sqlParams...); err == nil {
		var storeList2 []*Store4User
		for _, v := range storeList1 {
			distance := jxutils.Point2StoreDistance(lng, lat, v.Lng, v.Lat, v.DeliveryRangeType, v.DeliveryRange)
			if distance > 0 || (lng == jxutils.IntCoordinate2Standard(v.Lng) && lat == jxutils.IntCoordinate2Standard(v.Lat)) {
				v.Distance = distance
				storeList2 = append(storeList2, v)
			}
		}

		// 为了审核用
		if len(storeList2) == 0 {
			sql2 := `
				SELECT t1.*,
				city.name city_name
				FROM store t1
				JOIN place city ON city.code = t1.city_code
				WHERE t1.deleted_at = ?  AND t1.id = ?
			`
			sqlParams2 := []interface{}{
				// model.VendorIDJX, utils.DefaultTimeValue, model.StoreStatusDisabled,
				utils.DefaultTimeValue,
				// model.StoreStatusDisabled,
				// jxutils.StandardCoordinate2Int(0),
				// jxutils.StandardCoordinate2Int(10000),
				// jxutils.StandardCoordinate2Int(0),
				// jxutils.StandardCoordinate2Int(10000),
				// model.YES,
				102919, //商城模板店
			}
			dao.GetRows(dao.GetDB(), &storeList2, sql2, sqlParams2...)
			// if len(storeList2) > 1 {
			// 	storeList2 = storeList2[:1]
			// }
		}

		// 如果要求以步行距离来算
		if needWalkDistance {
			var coordList []*tencent_map.Coordinate
			for _, v := range storeList2 {
				coordList = append(coordList, &tencent_map.Coordinate{
					Lng: v.FloatLng,
					Lat: v.FloatLat,
				})
			}
			if distanceList, err2 := api.TencentMapAPI.BatchWalkingDistance(lng, lat, coordList); err2 == nil {
				for k, v := range storeList2 {
					v.WalkDistance = int(distanceList[k])
				}
			} else {
				return nil, err2
			}
		}

		sort.Sort(Store4UserList(storeList2))
		storeList = storeList2
		if len(storeList) > maxStoreCount4User {
			storeList = storeList[:maxStoreCount4User]
		}
	}
	return storeList, err
}

func GetVendorOrgCode(ctx *jxcontext.Context, vendorID int, vendorOrgCode, vendorType string) (vendorOrgs []*model.VendorOrgCode, err error) {
	return dao.GetVendorOrgCode(dao.GetDB(), vendorID, vendorOrgCode, vendorType)
}

func UpdateVendorOrgCode(ctx *jxcontext.Context, ID int, payload map[string]interface{}) (err error) {
	var (
		db            = dao.GetDB()
		vendorOrgCode = &model.VendorOrgCode{}
	)
	vendorOrgCode.ID = ID
	err = dao.GetEntity(db, vendorOrgCode)
	valid := dao.StrictMakeMapByStructObject(payload, vendorOrgCode, ctx.GetUserName())
	if len(valid) > 0 {
		if valid["key"] != nil {
			valid["vendorOrgCode"] = valid["key"]
			delete(valid, "key")
		}
		if valid["code"] != nil {
			valid["vendorID"] = valid["code"]
			delete(valid, "code")
		}
		if valid["name"] != nil {
			valid["comment"] = valid["name"]
			delete(valid, "name")
		}
		txDB, _ := dao.Begin(db)
		defer func() {
			if r := recover(); r != nil {
				dao.Rollback(db, txDB)
				panic(r)
			}
		}()
		if _, err = dao.UpdateEntityLogically(db, vendorOrgCode, valid, ctx.GetUserName(), nil); err != nil {
			dao.Rollback(db, txDB)
			return err
		}
		dao.Commit(db, txDB)
	}
	return err
}

func AddVendorOrgCode(ctx *jxcontext.Context, vendorOrgCode *model.VendorOrgCode) (err error) {
	var (
		db = dao.GetDB()
	)
	list, err := dao.GetVendorOrgCode(db, vendorOrgCode.VendorID, vendorOrgCode.VendorOrgCode, model.VendorOrgTypePlatform)
	if err != nil {
		return err
	}
	if len(list) > 0 {
		vendorOrgCode.ID = list[0].ID
		_, err = dao.UpdateEntity(db, vendorOrgCode, "token", "updated_at", "app_key", "app_secret", "comment", "vendor_org_code")
		return err
	}

	var userName string
	if ctx != nil {
		userName = ctx.GetUserName()
	} else {
		userName = "system"
	}
	dao.WrapAddIDCULDEntity(vendorOrgCode, userName)
	dao.CreateEntity(db, vendorOrgCode)
	return err
}
