package cms

import (
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/tencent_map"
	"math"
	"reflect"
	"regexp"
	"strconv"
	"strings"
	"time"

	"git.rosy.net.cn/baseapi/platformapi/autonavi"
	"git.rosy.net.cn/jx-callback/business/partner/purchase/ebai"

	"git.rosy.net.cn/baseapi/utils/errlist"

	"git.rosy.net.cn/jx-callback/globals/api2"

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

	"git.rosy.net.cn/jx-callback/business/auth2/authprovider/mobile"
	"git.rosy.net.cn/jx-callback/business/authz/autils"
	"git.rosy.net.cn/jx-callback/business/jxutils"
	"git.rosy.net.cn/jx-callback/business/partner"

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

const (
	SendMsgTypeOpenStoreRequest = "openStoreRequest"
	SendMsgTypeSuggestRequest   = "suggestRequest"
)

type SysConfigLimit struct {
	ValueType    reflect.Kind
	MinValue     int64
	MaxValue     int64
	AfterChanged func() error
}

var (
	serviceInfo               map[string]interface{}
	allowUpdatePlaceFieldsMap = map[string]bool{
		"name":      true,
		"enabled":   true,
		"mtpsPrice": true,
	}

	regexpMsgContentOpID = regexp.MustCompile(`"openid":"(.*?)"`)

	receiveMsgUsersMap = map[string][]string{
		SendMsgTypeOpenStoreRequest: []string{
			"石锋",
			// "x",
			// "周扬",
		},
		SendMsgTypeSuggestRequest: []string{
			"石锋",
			// "x",
			// "周扬",
			// "苏尹岚",
		},
	}
	needConfirmRequestMap = map[string]int{
		SendMsgTypeOpenStoreRequest: 1,
	}

	SysConfigLimitMap = map[string]*SysConfigLimit{
		model.ConfigSysEbaiBoxFee: &SysConfigLimit{
			ValueType: reflect.Int,
			MinValue:  0,
			MaxValue:  500,
			AfterChanged: func() (err error) {
				_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDEBAI}, nil, model.SyncFlagModifiedMask)
				return err
			},
		},
		model.ConfigSysMtwmBoxFee: &SysConfigLimit{
			ValueType: reflect.Int,
			MinValue:  0,
			MaxValue:  500,
			AfterChanged: func() (err error) {
				_, err = dao.SetStoreMapSyncStatus(dao.GetDB(), []int{model.VendorIDMTWM}, nil, model.SyncFlagModifiedMask)
				return err
			},
		},
		model.ConfigSysMtwmSkuBoxFee: &SysConfigLimit{
			ValueType: reflect.Int,
			MinValue:  0,
			MaxValue:  50,
			AfterChanged: func() (err error) {
				_, err = dao.SetStoreSkuSyncStatus(dao.GetDB(), model.VendorIDMTWM, nil, nil, model.SyncFlagModifiedMask)
				return err
			},
		},
	}

	AutonaviKeyList  = []string{autonavi.AMAPCyclingPlanKey1, autonavi.AMAPCyclingPlanKey2, autonavi.AMAPCyclingPlanKey3, autonavi.AMAPCyclingPlanKey4, autonavi.AMAPCyclingPlanKey5}
	AutonaviKeyIndex = 0
)

func InitServiceInfo(version string, buildTime time.Time, gitCommit string) {
	buildTimeStr := ""
	if !utils.IsTimeZero(buildTime) {
		buildTimeStr = utils.Time2Str(buildTime)
	}
	serviceInfo = map[string]interface{}{
		"startupTime": utils.Time2Str(time.Now()),
		"version":     version,
		"buildTime":   buildTimeStr,
		"gitCommit":   gitCommit,
		"metaData": map[string]interface{}{
			"skuNamePrefix":          model.SkuNamePrefixNames,
			"skuNameUnit":            model.UnitNames,
			"skuSpecUnit":            model.SpecUnitNames,
			"skuStatus":              model.SkuStatusName,
			"storeDeliveryRangeType": model.DeliveryRangeTypeName,
			"storeDeliveryType":      model.DeliveryTypeName,
			"storeStatus":            model.StoreStatusName,
			"categoryType":           model.CategoryTypeName,
			"vendorTypeName":         model.VendorTypeName,
			"vendorName":             model.VendorChineseNames,
			"orderStatus":            model.OrderStatusName,
			"waybillStatus":          model.WaybillStatusName,
			"orderTypeName":          model.OrderTypeName,
			"taskStatusName":         tasksch.TaskStatusName,
			"opRequestTypeName":      model.RequestTypeName,
			"opRequestStatusName":    model.RequestStatusName,
			"storeMsgSendStatusName": model.StoreMsgSendStatusName,
			"shopChineseNames":       model.ShopChineseNames,
			"printerVendorInfo":      model.PrinterVendorInfo,
			"printerStatusName":      partner.PrinterStatusName,
			"purchaseVendorInfo":     model.PurchaseVendorInfo,
			"afsReasonTypeName":      model.AfsReasonTypeName,
			"afsAppealTypeName":      model.AfsAppealTypeName,
			"actTypeName":            model.ActTypeName,
			"actStatusName":          model.ActStatusName,
			"actCreateTypeName":      model.ActCreateTypeName,
			"storeAuditStatusName":   model.StoreAuditStatusName,
			"configTypeName":         model.ConfigTypeName,
			"autoSaleAt":             AutoSaleAtStr,
			"userTypeName":           model.UserTypeName,
			"storePriceTypeName":     model.StorePriceTypeName,
			"payStatusName":          model.PayStatusName,
			"refundStatusName":       model.RefundStatusName,
			"autoReplyTypeName":      model.AutoReplyTypeName,
			"complaintReasons":       model.ComplaintReasons,
			"supplementType":         model.SupplementTypeName,
			"operateType":            model.OperateTypeName,
			"thingType":              model.ThingTypeName,
			"apiFunctionName":        model.ApiFunctionName,
			"vendorStatus":           model.VendorStatus,
			"couponsStatus":          model.CouponStatusName,
			"ebaiSupplierID":         ebai.EbaiSupplierIDMap,
			"ebaiSupplierInfo":       ebai.EbaiSupplierInfo,
		},
	}
}

func GetServiceInfo(ctx *jxcontext.Context) map[string]interface{} {
	return serviceInfo
}

func GetPlaces(ctx *jxcontext.Context, keyword string, includeDisabled bool, params map[string]interface{}) ([]*model.Place, error) {
	sql := ` 	
	SELECT *
	FROM place t1
	WHERE 1 = 1
	`
	if !includeDisabled {
		sql += " AND enabled = 1"
	}
	sqlParams := make([]interface{}, 0)
	if keyword != "" {
		sql += " AND (t1.name LIKE ?"
		sqlParams = append(sqlParams, "%"+keyword+"%")
		if keywordInt64, err2 := strconv.ParseInt(keyword, 10, 64); err2 == nil {
			sql += " OR t1.code = ?"
			sqlParams = append(sqlParams, keywordInt64)
		}
		sql += ")"
	}
	if params["parentCode"] != nil {
		sql += " AND t1.parent_code = ?"
		sqlParams = append(sqlParams, params["parentCode"])
	}
	if params["level"] != nil {
		sql += " AND t1.level = ?"
		sqlParams = append(sqlParams, params["level"])
	}
	sql += " ORDER BY t1.level, t1.name"
	places := []*model.Place{}
	return places, dao.GetRows(nil, &places, sql, sqlParams...)
}

func UpdatePlaces(ctx *jxcontext.Context, places []map[string]interface{}, userName string) (num int64, err error) {
	if len(places) == 0 {
		return 0, ErrMissingInput
	}
	updateFields := []string{}
	for k := range places[0] {
		if allowUpdatePlaceFieldsMap[k] {
			updateFields = append(updateFields, k)
		}
	}
	for _, place := range places {
		if place["code"] == nil {
			return 0, ErrMissingInput
		}
		placeid := &model.Place{}
		valid := dao.NormalMakeMapByFieldList(place, updateFields, userName)
		if num, err = dao.UpdateEntityLogically(nil, placeid, valid, userName, utils.Params2Map("Code", place["code"])); err != nil {
			return num, err
		}
	}
	return num, err
}

func UpdatePlace(ctx *jxcontext.Context, placeCode int, payload map[string]interface{}, userName string) (num int64, err error) {
	payload["code"] = placeCode
	return UpdatePlaces(ctx, []map[string]interface{}{payload}, userName)
}

func GetCoordinateDistrictCode(ctx *jxcontext.Context, lng, lat float64) (code int, err error) {
	return api.TencentMapAPI.GetCoordinateDistrictCode(lng, lat), nil
}

func GetCoordinateCityInfo(ctx *jxcontext.Context, lng, lat float64) (name string, err error) {
	name, _ = api.TencentMapAPI.GetCoordinateCityInfo(lng, lat)
	return name, err
}

func SendMsg2Somebody(ctx *jxcontext.Context, mobileNum, verifyCode, msgType, msgContent string) (err error) {
	if needConfirmRequestMap[msgType] == 1 {
		if _, err = mobile.AutherObj.VerifySecret(mobileNum, verifyCode); err != nil {
			return err
		}
	}
	db := dao.GetDB()
	//获取门店信息
	var (
		stores        []*model.Store
		authBinds     []*model.AuthBind
		order         *model.GoodsOrder
		storeName     string
		storeID       int
		vendorOrderID string
	)
	if mobileNum != "" {
		sql := `
		SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
	`
		sqlParams := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
		err = dao.GetRows(db, &stores, sql, sqlParams)
		if len(stores) > 0 {
			storeName = stores[0].Name
			storeID = stores[0].ID
		}
		if storeID == 0 {
			results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
			if len(results) > 0 {
				sql3 := `
				SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ? 
			`
				sqlParams3 := []interface{}{results[1], results[1]}
				err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
				if len(authBinds) > 0 {
					user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
					mobileNum = *user.Mobile
					sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
					err = dao.GetRows(db, &stores, sql, sqlParams4)
					if len(stores) > 0 {
						storeName = stores[0].Name
						storeID = stores[0].ID
					}
				}
			}
		}
	} else {
		results := regexpMsgContentOpID.FindStringSubmatch(msgContent)
		if len(results) > 0 {
			sql3 := `
				SELECT * FROM auth_bind WHERE auth_id = ? OR auth_id2 = ? 
			`
			sqlParams3 := []interface{}{results[1], results[1]}
			err = dao.GetRows(db, &authBinds, sql3, sqlParams3)
			if len(authBinds) > 0 {
				user, _ := dao.GetUserByID(db, "user_id", authBinds[0].UserID)
				mobileNum = *user.Mobile
				sql4 := `
					SELECT * FROM store WHERE (tel1 = ? OR tel2 = ?) AND deleted_at = ?
				`
				sqlParams4 := []interface{}{mobileNum, mobileNum, utils.DefaultTimeValue}
				err = dao.GetRows(db, &stores, sql4, sqlParams4)
				if len(stores) > 0 {
					storeName = stores[0].Name
					storeID = stores[0].ID
				}
			}
		}
	}
	sql2 := `
		SELECT * 
		  FROM goods_order 
		 WHERE IF(store_id <> '', store_id, jx_store_id) = ?
		 ORDER BY order_created_at DESC
		 LIMIT 1  
	`
	sqlParams2 := []interface{}{storeID}
	err = dao.GetRow(db, &order, sql2, sqlParams2)
	if order != nil {
		vendorOrderID = order.VendorOrderID
	}
	if storeID == 0 {
		vendorOrderID = ""
	}
	msgContent = msgContent + " 门店名称：" + storeName + " 门店ID：" + utils.Int2Str(storeID) + " 最新订单号：" + vendorOrderID
	for _, v := range receiveMsgUsersMap[msgType] {
		user, err2 := dao.GetUserByID(db, "name", v)
		if err2 == nil {
			ddmsg.SendUserMessage(dingdingapi.MsgTyeText, user.GetID(), msgType, msgContent)
		} else if err == nil {
			err = err2
		}
	}
	return err
}

func checkSysConfig(key, value string) (err error) {
	if limit := SysConfigLimitMap[key]; limit != nil {
		if limit.ValueType == reflect.Int {
			int64Value, err2 := strconv.ParseInt(value, 10, 64)
			if err = err2; err == nil {
				if int64Value < limit.MinValue || int64Value > limit.MaxValue {
					err = fmt.Errorf("配置%s,值%s超范围[%d,%d]", key, value, limit.MinValue, limit.MaxValue)
				}
			}
		}
	}
	return err
}

func onSysConfigChanged(key, value string) (err error) {
	if limit := SysConfigLimitMap[key]; limit != nil && limit.AfterChanged != nil {
		err = limit.AfterChanged()
	}
	return err
}

func checkConfig(opFlag int, configType, key, value string) (err error) {
	switch configType {
	case model.ConfigTypePricePack:
		if value != "" {
			pricePack := dao.PricePercentagePack2Obj(value)
			if pricePack == nil {
				err = fmt.Errorf("配置:%s不合法", value)
			}
		}
	case model.ConfigTypeFreightPack:
		if value != "" {
			freightPack := dao.FreightDeductionPack2Obj(value)
			if freightPack == nil {
				err = fmt.Errorf("配置:%s不合法", value)
			} else {
				var lastStage *model.FreightDeductionItem
				for _, v := range freightPack.FreightDeductionList {
					if lastStage != nil && lastStage.DeductFreight > v.DeductFreight {
						err = fmt.Errorf("免运设置不合理:门槛:%s,免运金额:%s,门槛:%s,免运金额:%s",
							jxutils.IntPrice2StandardString(int64(lastStage.BeginPrice)), jxutils.IntPrice2StandardString(int64(lastStage.DeductFreight)),
							jxutils.IntPrice2StandardString(int64(v.BeginPrice)), jxutils.IntPrice2StandardString(int64(v.DeductFreight)))
						return err
					}
					lastStage = v
				}
			}
		}
	case model.ConfigTypeBank:
		if value != "" {
			if model.BankName[key] == "" {
				err = fmt.Errorf("此银行代码:%s不支持，请联系开发", value)
			}
		}
	case model.ConfigTypeRole:
	case model.ConfigTypeSys:
		if opFlag&( /*model.SyncFlagNewMask|*/ model.SyncFlagDeletedMask) != 0 {
			err = fmt.Errorf("系统参数只支持修改或添加，不支持删除")
		} else {
			err = checkSysConfig(key, value)
		}
	case model.ConfigTypeJxStore:
	case model.ConfigTypeCookie:
	case model.ConfigTypeDiscountCard:
	default:
		err = fmt.Errorf("当前只支持配置:%s, 传入的配置类型:%s", utils.Format4Output(model.ConfigTypeName, true), configType)
	}
	return err
}

func AddConfig(ctx *jxcontext.Context, key, configType, value string) (err error) {
	if err = checkConfig(model.SyncFlagNewMask, configType, key, value); err != nil {
		return err
	}

	db := dao.GetDB()
	conf := &model.NewConfig{
		Key:   key,
		Type:  configType,
		Value: value,
	}
	dao.WrapAddIDCULDEntity(conf, ctx.GetUserName())
	err = dao.CreateEntity(db, conf)
	if configType == model.ConfigTypeSys && err == nil {
		err = onSysConfigChanged(key, value)
	}
	return err
}

func DeleteConfig(ctx *jxcontext.Context, key, configType string) (err error) {
	if err = checkConfig(model.SyncFlagDeletedMask, configType, key, ""); err != nil {
		return err
	}
	db := dao.GetDB()
	switch configType {
	case model.ConfigTypePricePack:
		storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
		if err = err2; err == nil {
			var storeInfo []string
			for _, v := range storeMapList {
				storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
			}
			if len(storeInfo) > 0 {
				err = fmt.Errorf("还有门店在使用价格包:%s，门店信息:%s", key, strings.Join(storeInfo, ","))
			}
		}
	case model.ConfigTypeFreightPack:
		storeMapList, err2 := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
		if err = err2; err == nil {
			var storeInfo []string
			for _, v := range storeMapList {
				if v.FreightDeductionPack == key {
					storeInfo = append(storeInfo, fmt.Sprintf("门店:%d, 平台:%s", v.StoreID, model.VendorChineseNames[v.VendorID]))
				}
			}
			if len(storeInfo) > 0 {
				err = fmt.Errorf("还有门店在使用价格包:%s，门店信息:%s", key, strings.Join(storeInfo, ","))
			}
		}
	case model.ConfigTypeBank:
		//todo
		return fmt.Errorf("暂不支持删除银行")
	case model.ConfigTypeRole:
		errList := errlist.New()
		userIDs, err2 := api2.RoleMan.GetRoleUserList(autils.NewRole(key, 0))
		if err = err2; err == nil && len(userIDs) > 0 {
			userList, totalCount, err2 := dao.GetUsers(dao.GetDB(), 0, "", userIDs, nil, nil, 0, -1)
			if err = err2; err == nil && totalCount > 0 {
				// todo
				// err = fmt.Errorf("还有人员在使用角色:%s，人员信息:%s", key, utils.MustMarshal(utils.Struct2Map(userList, "compact")))
				err = fmt.Errorf("还有人员在使用角色:%s，人员信息:%s", key, utils.Format4Output(userList, false))
			}
		}
		errList.AddErr(err)
		storeList, err2 := dao.GetStoreList(db, nil, nil, nil, nil, nil, key)
		if err = err2; err == nil && len(storeList) > 0 {
			storeIDs := make([]int, len(storeList))
			for k, v := range storeList {
				storeIDs[k] = v.ID
			}
			err = fmt.Errorf("还有门店在使用角色:%s，门店信息:%s", key, utils.MustMarshal(storeIDs))
		}
		errList.AddErr(err)
		err = errList.GetErrListAsOne()
	}
	if err == nil {
		_, err = dao.DeleteEntityLogically(db, &model.NewConfig{}, nil, ctx.GetUserName(), map[string]interface{}{
			"Key":  key,
			"Type": configType,
		})
	}
	if configType == model.ConfigTypeSys && err == nil {
		err = onSysConfigChanged(key, "")
	}
	return err
}

func UpdateConfig(ctx *jxcontext.Context, key, configType, value string) (hint string, err error) {
	if key == "" {
		return "", fmt.Errorf("修改配置必须给定key")
	}
	if err = checkConfig(model.SyncFlagModifiedMask, configType, key, value); err != nil {
		return "", err
	}
	hint = "1"

	db := dao.GetDB()
	txDB, _ := dao.Begin(db)
	defer func() {
		if r := recover(); r != nil {
			dao.Rollback(db, txDB)
			panic(r)
		}
	}()
	configList, err := dao.QueryConfigs(db, key, configType, "")
	if err != nil {
		dao.Rollback(db, txDB)
		return "", err
	}
	if _, err = dao.UpdateEntityLogically(db, configList[0], map[string]interface{}{
		"Value": value,
	}, ctx.GetUserName(), nil); err != nil {
		dao.Rollback(db, txDB)
		return "", err
	}
	switch configType {
	case model.ConfigTypePricePack:
		storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, key, "", "")
		if err != nil {
			dao.Rollback(db, txDB)
			return "", err
		}
		dao.Commit(db, txDB)
		vendorStoreMap := make(map[int][]int)
		for _, v := range storeMapList {
			vendorStoreMap[v.VendorID] = append(vendorStoreMap[v.VendorID], v.StoreID)
		}
		for vendorID, storeIDs := range vendorStoreMap {
			if vendorID != model.VendorIDJX {
				dao.SetStoreSkuSyncStatus(db, vendorID, storeIDs, nil, model.SyncFlagPriceMask)
			} else {
				hint, err = ReCalculateJxPrice(db, ctx, storeIDs)
			}
		}
	case model.ConfigTypeFreightPack:
		dao.Commit(db, txDB)
		storeMapList, err := dao.GetStoresMapList(db, nil, nil, nil, model.StoreStatusAll, model.StoreIsSyncYes, "", "", "")
		if err != nil {
			return "", err
		}
		for _, v := range storeMapList {
			var storeMapList2 []*model.StoreMap
			if v.FreightDeductionPack == key {
				storeMapList2 = append(storeMapList2, v)
			}
			if len(storeMapList2) > 0 {
				task := tasksch.NewParallelTask("同步门店配送免运", tasksch.NewParallelConfig().SetIsContinueWhenError(true), ctx,
					func(task *tasksch.ParallelTask, batchItemList []interface{}, params ...interface{}) (retVal interface{}, err error) {
						storeMap := batchItemList[0].(*model.StoreMap)
						_, err = CurVendorSync.SyncStore(ctx, db, storeMap.VendorID, storeMap.StoreID, false, ctx.GetUserName())
						return retVal, err
					}, storeMapList2)
				tasksch.HandleTask(task, nil, true).Run()
				if len(storeMapList2) < 5 {
					_, err = task.GetResult(0)
				} else {
					hint = task.GetID()
				}
			}
		}
	default:
		dao.Commit(db, txDB)
	}
	if configType == model.ConfigTypeSys && err == nil {
		err = onSysConfigChanged(key, value)
	}
	return hint, err
}

func QueryConfigs(key, configType, keyword string) (configList []*model.NewConfig, err error) {
	return dao.QueryConfigs(dao.GetDB(), key, configType, keyword)
}

func GetCityBankBranches(ctx *jxcontext.Context, cityCode int, bankCode string) (info map[int]map[string][]string, err error) {
	list, err := dao.GetCityBankBranches(dao.GetDB(), cityCode, bankCode)
	if err == nil && len(list) > 0 {
		info = make(map[int]map[string][]string)
		for _, v := range list {
			if info[v.CityCode] == nil {
				info[v.CityCode] = make(map[string][]string)
			}
			info[v.CityCode][v.PayeeBankCode] = append(info[v.CityCode][v.PayeeBankCode], v.PayeeBankBranchName)
		}
	}
	return info, err
}

// GetSToURidingDistance 获取商家与用户间步行距离
func GetSToURidingDistance(sLng, sLat, uLng, uLat float64, orderId string) (stepInfo interface{}, err error) {
	coordList, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
		Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
		Type:      tencent_map.CoordinateChangeTypeBaidu,
	})

	if err == nil && len(coordList) == 2 {
		param := &tencent_map.TencentCyclingPlanningReq{
			From: fmt.Sprintf("%s,%s", coordList[0].Lat, coordList[0].Lng),
			To:   fmt.Sprintf("%s,%s", coordList[1].Lat, coordList[1].Lng),
		}
		if stepInfo, err = api.TencentMapAPI.WalkingDistance(param); err == nil {
			return stepInfo, nil
		}
	}
	return 0, err
}

// GetSToURidingDistance2 获取商家与用户间步行距离
func GetSToURidingDistance2(sLng, sLat, uLng, uLat float64, orderId string, vendors []int64) (wayBill *model.Waybill, err error) {
	var (
		db         = dao.GetDB()
		vendorMaps = map[int]int{model.VendorIDDada: 1, model.VendorIDFengNiao: 1, model.VendorIDMTPS: 1, model.VendorIDUUPT: 1, model.VendorIDSFPS: 1}
	)

	for {
		// 骑手坐标
		waybills, err := dao.GetWaybills(db, orderId, vendors)
		if err != nil {
			return nil, err
		}
		if len(waybills) == model.NO {
			return nil, fmt.Errorf("请先创建运单,或者转自配送")
		}
		for _, v := range waybills {
			// 获取骑行路线图
			if v.OriginalData == "" && v.WaybillVendorID == model.VendorJXFakeWL {
				originalData, distance, durationTime, err2 := GetCyclingLine(sLng, sLat, uLng, uLat)
				if err2 == nil && len(originalData) != model.NO {
					v.OriginalData = strings.Join(originalData, ";")
					v.Distance = distance
					v.DurationTime = durationTime + 500
				}
			}

			if vendorMaps[v.WaybillVendorID] == model.YES {
				// 如果是三方配送,更新骑手信息
				if handler := partner.GetDeliveryPlatformFromVendorID(v.WaybillVendorID); handler != nil {
					riderInfo, _ := handler.Handler.GetRiderInfo(v.VendorOrderID, v.ID+1000000, v.VendorWaybillID)
					if riderInfo != nil {
						if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
							riderInfo.Longitude += "0"
						}
						if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
							riderInfo.Latitude += "0"
						}
						v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
						if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
							v.CourierName = riderInfo.CourierName
							v.CourierMobile = riderInfo.CourierPhone
						}
					}
				}
			} else {
				// 如果是平台配送,获取骑手信息
				if handler := partner.GetPurchaseOrderHandlerFromVendorID(v.WaybillVendorID); handler != nil {
					riderInfo, _ := handler.OrderLogisticsStatus(v.VendorOrderID)
					if riderInfo != nil {
						if len(riderInfo.Longitude) < len("104.065861") || riderInfo.Longitude != "" {
							riderInfo.Longitude += "0"
						}
						if len(riderInfo.Latitude) < len("27.934441") || riderInfo.Latitude != "" {
							riderInfo.Latitude += "0"
						}
						v.CourierCoordinate = fmt.Sprintf("%s,%s", riderInfo.Longitude, riderInfo.Latitude)
						if (v.CourierName == "" || v.CourierMobile == "") && riderInfo.CourierName != "" {
							v.CourierName = riderInfo.CourierName
							v.CourierMobile = riderInfo.CourierPhone
						}
					}
				}
			}

			// 当这个运单为假物流/门店真实自送/获取运单骑手信息为空的时候使用假的骑手信息
			if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData != "" {
				riderLine := strings.Split(v.OriginalData, ";") // 路线坐标点

				courierDistance := float64(time.Now().Unix()-v.WaybillCreatedAt.Unix()) * (float64(v.Distance) / float64(v.DurationTime)) // 当前骑手骑行距离
				if courierDistance >= float64(v.Distance) {
					courierDistance = float64(v.Distance)
				}
				nowCourierDrop := int64(math.Ceil((courierDistance / float64(v.Distance)) * float64(len(riderLine)))) // 当前骑手骑行距离,占中的骑行距离百分比.
				if nowCourierDrop >= int64(len(riderLine)) {
					v.CourierCoordinate = riderLine[nowCourierDrop-1]
				}
				if nowCourierDrop <= 0 {
					v.CourierCoordinate = riderLine[0]
				}
				if v.Status >= model.WaybillStatusDelivered {
					v.CourierCoordinate = riderLine[len(riderLine)-1]
				}
				if v.Status == model.WaybillStatusCourierArrived {
					order, _ := partner.CurOrderManager.LoadOrder(orderId, v.OrderVendorID)
					storeDetail, err := dao.GetStoreDetail2(dao.GetDB(), order.JxStoreID, order.VendorStoreID, order.VendorID)
					if err == nil && storeDetail != nil {
						v.CourierCoordinate = fmt.Sprintf("%s,%s", utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lng)), utils.Float64ToStr(jxutils.IntCoordinate2Standard(storeDetail.Lat)))
					}
				}
				if v.CourierCoordinate == "" {
					v.CourierCoordinate = riderLine[nowCourierDrop]
				}

			} else if (v.WaybillVendorID == model.VendorJXFakeWL || v.WaybillVendorID == model.VendorIDUnknown || v.CourierCoordinate == "") && v.OriginalData == "" {
				lng := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLng-uLng)/float64(300)))
				lat := utils.Str2Float64(fmt.Sprintf("%0.6f", (sLat-uLat)/float64(300)))
				originalData := make([]string, 0, 0)
				originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", sLng, sLat))
				var nLng float64
				var nLat float64
				for i := 1; i <= 300; i++ {
					if sLng > uLng {
						nLng = sLng - (lng * float64(i))
					} else {
						nLng = sLng + (lng * float64(i))
					}
					if sLat > uLat {
						nLat = sLat - (lat * float64(i))
					} else {
						nLat = sLat + (lat * float64(i))
					}
					fakeCourier := fmt.Sprintf("%.6f,%.6f", nLng, nLat)
					originalData = append(originalData, fakeCourier)
				}
				originalData = append(originalData, fmt.Sprintf("%.6f,%.6f", uLng, uLat))

				v.Distance = 5001    // 距离,固定
				v.DurationTime = 600 // 固定骑行时间
				v.OriginalData = strings.Join(originalData, ";")
				v.CourierCoordinate = originalData[0]
			}

			dao.UpdateEntity(db, v, "OriginalData", "CourierCoordinate", "Distance", "DurationTime")
			if v.CourierName == "" || v.CourierMobile == "" {
				v.CourierName = "暂无骑手"
				v.CourierMobile = "暂无电话"
			}
			return v, nil
		}

	}
}

// GetCyclingLine 获取骑行路线
func GetCyclingLine(sLng, sLat, uLng, uLat float64) (polyLineList []string, distance, duration int64, err error) {
	// 百度
	/*	var coords []*baidunavi.Coordinate
		coords = append(coords, &baidunavi.Coordinate{
			Lng: sLng,
			Lat: sLat,
		}, &baidunavi.Coordinate{
			Lat: uLat,
			Lng: uLng,
		})*/

	// 高德坐标转换成百度坐标
	/*coords, err := api.TencentMapAPI.TencentCoordinateChange(&tencent_map.TencentCoordinateChangeReq{
		Locations: fmt.Sprintf("%.6f,%.6f;%.6f,%.6f", sLat, sLng, uLat, uLng),
		Type:      tencent_map.CoordinateChangeTypeBaidu,
	})
	if err != nil || len(coords) <= model.NO {
		return nil, 0, 0, err
	}
	*/
	distance, duration, polyLineList, err = api.TencentMapAPI.TencentCyclingPlanning(&tencent_map.TencentCyclingPlanningReq{
		From: fmt.Sprintf("%.6f,%.6f", sLat, sLng),
		To:   fmt.Sprintf("%.6f,%.6f", uLat, uLng),
	})
	return
}
