package mtps

import (
	"crypto/sha1"
	"errors"
	"fmt"
	"git.rosy.net.cn/baseapi/platformapi/mtpsapi"
	"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/business/partner"
	"git.rosy.net.cn/jx-callback/business/partner/delivery"
	"git.rosy.net.cn/jx-callback/globals"
	"git.rosy.net.cn/jx-callback/globals/api"
	"github.com/astaxie/beego/client/orm"
	beego "github.com/astaxie/beego/server/web"
	"net/http"
	"net/url"
	"sort"
	"strings"
)

const (
	// maxOrderPrice  = 6399 // 单位为分，达达最大价格，超过这个价格配送费会增加
	maxOrderWeight = 5000 // 5公斤
)

var (
	ErrCanNotFindMTPSStore = errors.New("不能找到美团配送站点配置")
	ErrStoreNoPriceInfo    = errors.New("找不到门店的美团配送价格信息")
)

var (
	curDeliveryHandler *DeliveryHandler
)

type DeliveryHandler struct {
}

func init() {
	if api.MtpsAPI != nil {
		curDeliveryHandler = new(DeliveryHandler)
		partner.RegisterDeliveryPlatform(curDeliveryHandler, true)
	}
}

func (c *DeliveryHandler) GetVendorID() int {
	return model.VendorIDMTPS
}

func OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
	return curDeliveryHandler.OnWaybillMsg(msg)
}

func OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) {
	return curDeliveryHandler.OnWaybillExcept(msg)
}

func (c *DeliveryHandler) OnWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
	jxutils.CallMsgHandler(func() {
		retVal = c.onWaybillMsg(msg)
	}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDMTPS))
	return retVal
}

func (c *DeliveryHandler) OnWaybillExcept(msg *mtpsapi.CallbackOrderExceptionMsg) (retVal *mtpsapi.CallbackResponse) {
	jxutils.CallMsgHandler(func() {
		order := &model.Waybill{
			VendorWaybillID:  msg.MtPeisongID,
			VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID),
			WaybillVendorID:  model.VendorIDMTPS,
			CourierName:      msg.CourierName,
			CourierMobile:    msg.CourierPhone,
			Status:           model.WaybillStatusUnknown, // todo 这里要再确定一下是否只要收到订单异常消息就只简单当成一个消息
			VendorStatus:     utils.Int2Str(msg.ExceptionCode),
			StatusTime:       utils.Timestamp2Time(msg.Timestamp),
		}
		order.VendorOrderID, order.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
		retVal = mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), "mtps OnWaybillExcept")
	}, jxutils.ComposeUniversalOrderID(msg.OrderID, model.VendorIDDada))
	return retVal
}

func (c *DeliveryHandler) onWaybillMsg(msg *mtpsapi.CallbackOrderMsg) (retVal *mtpsapi.CallbackResponse) {
	order := c.callbackMsg2Waybill(msg)
	switch msg.Status {
	case mtpsapi.OrderStatusWaitingForSchedule:
		data, err := api.MtpsAPI.QueryOrderStatus(msg.DeliveryID, msg.MtPeisongID)
		if err != nil {
			return mtpsapi.Err2CallbackResponse(err, fmt.Sprintf("%s", "获取订单状态错误"))
		}
		order.DesiredFee = utils.Float64TwoInt64(utils.MustInterface2Float64(data["delivery_fee"]) * 100)
		order.Status = model.WaybillStatusNew
	case mtpsapi.OrderStatusAccepted:
		data, err := api.MtpsAPI.QueryOrderStatus(msg.DeliveryID, msg.MtPeisongID)
		if err != nil {
			return mtpsapi.Err2CallbackResponse(err, fmt.Sprintf("%s", "获取订单状态错误"))
		}
		order.DesiredFee = utils.Float64TwoInt64(utils.MustInterface2Float64(data["delivery_fee"]) * 100)
		order.Status = model.WaybillStatusAccepted
		order.Remark = order.CourierName + "，" + order.CourierMobile
	case mtpsapi.OrderStatusPickedUp:
		order.Status = model.WaybillStatusDelivering
	case mtpsapi.OrderStatusDeliverred:
		order.Status = model.WaybillStatusDelivered
	case mtpsapi.OrderStatusCanceled:
		order.Status = model.WaybillStatusCanceled
	default:
		globals.SugarLogger.Warnf("onWaybillMsg unknown msg:%v", msg)
		return mtpsapi.SuccessResponse
	}
	order2, _ := partner.CurOrderManager.LoadOrder(order.VendorOrderID, order.OrderVendorID)
	// order2, _ := dao.GetSimpleOrder(dao.GetDB(), order.VendorOrderID)
	//查不到订单可能就是果园的订单
	if order2 == nil {
		c.pushToGy(msg)
		return mtpsapi.SuccessResponse
	}
	// 加入调度器
	return mtpsapi.Err2CallbackResponse(partner.CurOrderManager.OnWaybillStatusChanged(order), order.VendorStatus)
}

func (c *DeliveryHandler) pushToGy(msg *mtpsapi.CallbackOrderMsg) {
	cl := http.Client{}
	params := make(map[string]interface{})
	params["mt_peisong_id"] = msg.MtPeisongID
	params["courier_name"] = msg.CourierName
	params["delivery_id"] = msg.DeliveryID
	params["appkey"] = msg.AppKey
	params["order_id"] = msg.OrderID
	params["courier_phone"] = msg.CourierPhone
	params["status"] = msg.Status
	params["timestamp"] = msg.Timestamp
	params["cancel_reason_id"] = msg.CancelReasonId
	params["cancel_reason"] = msg.CancelReason
	urls := utils.Map2URLValues(params)
	sign := signParams(urls)
	params["sign"] = sign
	globals.SugarLogger.Debugf("pushToGy", utils.Format4Output(msg, false))
	request, err := http.NewRequest(http.MethodPost, "http://callback-jxgy.jxc4.com/mtps/status", strings.NewReader(utils.Map2URLValues(params).Encode()))
	if err != nil {
		return
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
	cl.Do(request)
}

func signParams(params url.Values) string {
	keys := make([]string, 0)
	for k := range params {
		if k != "sign" {
			keys = append(keys, k)
		}
	}

	sort.Strings(keys)
	finalStr := "b1M}9?:sTbsB[OF2gNORnN(|(iy9rB8(`7]|[wGLnbmt`evfM>E:A90DjHAW:UPE"
	for _, key := range keys {
		valStr := strings.Join(params[key], "")
		if valStr != "" {
			finalStr += key + valStr
		}
	}

	// baseapi.SugarLogger.Debug(finalStr)
	return fmt.Sprintf("%x", sha1.Sum([]byte(finalStr)))
}

func (c *DeliveryHandler) callbackMsg2Waybill(msg *mtpsapi.CallbackOrderMsg) (retVal *model.Waybill) {
	retVal = &model.Waybill{
		VendorWaybillID:  msg.MtPeisongID,
		VendorWaybillID2: utils.Int64ToStr(msg.DeliveryID),
		WaybillVendorID:  model.VendorIDMTPS,
		CourierName:      msg.CourierName,
		CourierMobile:    msg.CourierPhone,
		VendorStatus:     utils.Int2Str(msg.Status),
		StatusTime:       utils.Timestamp2Time(msg.Timestamp),
		Remark:           msg.CancelReason,
	}
	retVal.VendorOrderID, retVal.OrderVendorID = jxutils.SplitUniversalOrderID(msg.OrderID)
	return retVal
}

// 老方法是自己计算
//func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
//	db := dao.GetDB()
//	deliveryFeeInfo = &partner.WaybillFeeInfo{}
//	deliveryFeeInfo.RefDeliveryFee, deliveryFeeInfo.RefAddFee, err = delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
//	if err == nil {
//		if _, err = c.getMTPSShopID(order, db); err == nil {
//			deliveryFeeInfo.DeliveryFee = deliveryFeeInfo.RefDeliveryFee
//		}
//	}
//	return deliveryFeeInfo, err
//}

// 新方法平台返回
func (c *DeliveryHandler) GetWaybillFee(order *model.GoodsOrder) (deliveryFeeInfo *partner.WaybillFeeInfo, err error) {
	shopWeight := float64(order.Weight) / float64(order.Weight)
	if shopWeight > 50 {
		return nil, fmt.Errorf("订单重量超过五十千克,无法出货")
	}

	deliveryFeeInfo = &partner.WaybillFeeInfo{}
	// 获取送货单id
	deliveryID := c.getDeliveryID(order)
	shopId, err := c.getMTPSShopID(order, dao.GetDB())
	if err != nil {
		return nil, err
	}

	deliveryFeeInfo.RefDeliveryFee, deliveryFeeInfo.RefAddFee, err = api.MtpsAPI.PreCreateByShop(&mtpsapi.PreCreateByShopParam{
		DeliveryID:           deliveryID,
		OrderID:              order.VendorOrderID,
		ShopID:               shopId,
		DeliveryServiceCode:  mtpsapi.DeliveryServiceCodeRapid,
		ReceiverName:         order.ConsigneeName,
		ReceiverAddress:      order.ConsigneeAddress,
		ReceiverPhone:        order.ConsigneeMobile,
		ReceiverLng:          order.ConsigneeLng,
		ReceiverLat:          order.ConsigneeLat,
		GoodsValue:           utils.Int64ToFloat64(order.ActualPayPrice) / 100,
		GoodsWeight:          float64(int(shopWeight*100)) / 100, // 系统重量转换为千克
		PayTypeCode:          0,
		ExpectedDeliveryTime: mtpsapi.DeliveryServiceCodeRapid, // 4002飞速达,4011快速达,4012及时达,4013集中送
		OuterOrderSourceDesc: "101",
	})
	deliveryFeeInfo.DeliveryFee = deliveryFeeInfo.RefDeliveryFee

	return deliveryFeeInfo, err
}

// IDeliveryPlatformHandler（美团配送）
func (c *DeliveryHandler) CreateWaybill(order *model.GoodsOrder, maxDeliveryFee int64) (bill *model.Waybill, err error) {
	db := dao.GetDB()
	// 检查配送平台是否被禁用
	vendorOrgCode, err := dao.GetVendorOrgCode(db, model.VendorIDFengNiao, "", model.VendorOrgTypeDelivery)
	if err != nil {
		return nil, err
	}
	if len(vendorOrgCode) > 0 && vendorOrgCode[0].IsOpen == model.YES {
		return nil, fmt.Errorf("此平台配送已被系统关闭，暂不发配送 [%v]", vendorOrgCode[0].Comment)
	}

	// 自定义计算预估费用
	//deliveryFee, _, err := delivery.CalculateOrderDeliveryFee(order, time.Now(), db)
	//if err != nil {
	//	return nil, err
	//}
	// 运费预警
	//if err = delivery.CallCreateWaybillPolicy(deliveryFee, maxDeliveryFee, order, model.VendorIDMTPS); err != nil {
	//	return nil, err
	//}

	// 忽略坐标转换错误，即使是转换出错，也只能当成转换成功来处理，底层会有错误日志输出
	lngFloat, latFloat, _ := jxutils.IntCoordinate2MarsStandard(order.ConsigneeLng, order.ConsigneeLat, order.CoordinateType)
	billParams := &mtpsapi.CreateOrderByShopParam{
		OrderID:             jxutils.ComposeUniversalOrderID(order.VendorOrderID, order.VendorID),
		DeliveryServiceCode: mtpsapi.DeliveryServiceCodeRapid,
		ReceiverName:        utils.FilterMb4(order.ConsigneeName),
		ReceiverAddress:     utils.FilterMb4(order.ConsigneeAddress),
		ReceiverPhone:       order.ConsigneeMobile,
		CoordinateType:      model.CoordinateTypeMars,
		ReceiverLng:         jxutils.StandardCoordinate2Int(lngFloat),
		ReceiverLat:         jxutils.StandardCoordinate2Int(latFloat),
		GoodsValue:          jxutils.IntPrice2Standard(order.ActualPayPrice), // todo 超价处理
		GoodsWeight:         float64(jxutils.IntWeight2Float(limitOrderWeight(order.Weight))),
		// ExpectedDeliveryTime: order.ExpectedDeliveredTime.Unix(),
		OrderType: mtpsapi.OrderTypeASAP,
	}

	// 获取送货单id
	billParams.DeliveryID = c.getDeliveryID(order)
	// 获取商铺id
	if billParams.ShopID, err = c.getMTPSShopID(order, db); err != nil {
		return nil, err
	}

	// 获取美团入参结构体
	goods := &mtpsapi.GoodsDetail{
		Goods: []*mtpsapi.GoodsItem{},
	}
	goodItemMap := map[string]*mtpsapi.GoodsItem{}
	for _, sku := range order.Skus {
		goodItem := &mtpsapi.GoodsItem{
			GoodCount: sku.Count,
			GoodPrice: jxutils.IntPrice2Standard(sku.SalePrice),
		}
		goodItem.GoodName, goodItem.GoodUnit = jxutils.GetNameAndUnitFromSkuName(sku.SkuName)
		// 好像SKU名不能重复，否则会报错，尝试处理一下
		if item, ok := goodItemMap[goodItem.GoodName]; !ok {
			goods.Goods = append(goods.Goods, goodItem)
			goodItemMap[goodItem.GoodName] = goodItem
		} else {
			item.GoodCount += goodItem.GoodCount
		}
	}

	billParams.Note = utils.FilterMb4("客户电话：" + order.ConsigneeMobile + "," + order.BuyerComment + "，取货失败或配送遇到问题请联系18048531223，禁止未配送直接完成定单！")
	billParams.GoodsDetail = string(utils.MustMarshal(goods))
	billParams.GoodsPickupInfo = fmt.Sprintf("%s第%d号单", model.VendorChineseNames[order.VendorID], order.OrderSeq)
	billParams.PoiSeq = fmt.Sprintf("#%d", order.OrderSeq)
	if !globals.EnableStoreWrite {
		return nil, fmt.Errorf("测试环境不能真正创建运单")
	}

	//  通知美团订单，获取返回订单配送费
	result, err := api.MtpsAPI.CreateOrderByShop2(billParams)
	if err != nil {
		globals.SugarLogger.Debugf("CreateWaybill failed, orderID:%s, billParams:%v, error:%v", order.VendorOrderID, billParams, err)
		return nil, err
	}

	bill = &model.Waybill{
		VendorOrderID:    order.VendorOrderID,
		OrderVendorID:    order.VendorID,
		VendorWaybillID:  result.MtPeisongID,
		VendorWaybillID2: utils.Int64ToStr(result.DeliveryID),
		WaybillVendorID:  model.VendorIDMTPS,
		DesiredFee:       utils.Float64TwoInt64(result.DeliveryFee),
	}
	// 当前运单总费大于配送阈值15，日志打印提示
	delivery.OnWaybillCreated(bill)

	return bill, err
}

func (c *DeliveryHandler) CancelWaybill(bill *model.Waybill, cancelReasonID int, cancelReason string) (err error) {
	cancelReasonID = mtpsapi.CancelReasonMerchantOther
	if cancelReason == "" {
		cancelReason = "顾客主动取消"
	}
	_, err = api.MtpsAPI.CancelOrder(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, cancelReasonID, cancelReason)
	return err
}

func (c *DeliveryHandler) getDeliveryID(order *model.GoodsOrder) (retVal int64) {
	// jxorder表当前已经有50多万条记录了，加100万避免冲突
	// 508505
	return order.ID + 1000000
}

func (c *DeliveryHandler) getMTPSShopID(order *model.GoodsOrder, db *dao.DaoDB) (retVal string, err error) {
	saleStoreID := jxutils.GetSaleStoreIDFromOrder(order)
	storeCourierList, err2 := dao.GetOpenedStoreCouriersByStoreID(db, saleStoreID, model.VendorIDMTPS)
	if err = err2; err != nil && err != orm.ErrNoRows {
		return "", err
	}
	if len(storeCourierList) == 0 {
		return "", partner.ErrStoreHaveNoCourier
	}
	retVal = storeCourierList[0].VendorStoreID
	if beego.BConfig.RunMode == "dev" {
		retVal = "test_0001"
	}
	return retVal, nil
}

func limitOrderWeight(weight int) int {
	if weight > maxOrderWeight {
		return maxOrderWeight
	}
	return weight
}

func (c *DeliveryHandler) ComplaintRider(bill *model.Waybill, resonID int, resonContent string) (err error) {
	if globals.EnableStoreWrite {
		err = api.MtpsAPI.EvaluateRider(utils.Str2Int64(bill.VendorWaybillID2), bill.VendorWaybillID, 1, resonContent)
	}
	return err
}

func (c *DeliveryHandler) GetRidderPosition(ctx *jxcontext.Context, vendorOrgCode, vendorOrderID, vendorWaybillID, vendorWaybillID2 string) (lng, lat float64, err error) {
	intLng, intLat, err := api.MtpsAPI.RiderLocation(utils.Str2Int64(vendorWaybillID2), vendorWaybillID)
	if err == nil {
		lng = jxutils.IntCoordinate2Standard(intLng)
		lat = jxutils.IntCoordinate2Standard(intLat)
	}
	return lng, lat, err
}
