package jdapi

import (
	"fmt"
	"git.rosy.net.cn/baseapi"
	"io/ioutil"
	"net/http"
	"strings"

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

const (
	CallbackPrefix = "/djsw/"
)

// 如下的常量其实都是京东回调消息的
const (
	OrderStatusAddComment    = "12001"
	OrderStatusModifyComment = "12006"
	OrderStatusTipChanged    = "12008"

	OrderStatusPurchased = "41000" // 也即待处理，JD的消息很怪，新订单消息发过来是32000，但如果不是自动接单的，去查却是41000？，接单后才变为32000

	OrderStatusPayed = "31020" // 已付款

	StatusIDNewOrder          = "32000"
	OrderStatusWaitOutStore   = "32000"
	OrderStatusAdjust         = "33080"
	StatusIDWaitOutStore      = "32001"
	OrderStatusFinishedPickup = "2"
	OrderStatusDelivering     = "33040"

	OrderStatusDelivered = "33060"
	OrderStatusFinished  = "90000"
	OrderStatusCanceled  = "20020"

	OrderStatusVenderAgreeCancel  = "20031" // 商家同意取消申请
	OrderStatusVenderRejectCancel = "20032" // 商家驳回取消申请

	OrderStatusUserApplyCancel = "20030" // 这个其实不是一个状态，是一个动作
	OrderStatusLocked          = "20010"
	OrderStatusUnlocked        = "20050"
	OrderStatusInfoChanged     = "1" // 订单信息变更消息

	OrderStatusPayFinishedSettle = "330901" // 订单支付完成应结
	OrderStatusAdjustSettle      = "330902" // 订单调整后应结
	OrderStatusSwitch2SelfSettle = "330903" // 订单众包配送转自送后应结

	PromotionStatusSingleOK    = "35" // 单品直降活动已生效
	PromotionStatusLimitTimeOK = "45" // 限时抢活动已生效
)

const (
	StatusIDAddStore    = "12003" // 新增门店消息
	StatusIDDelStore    = "12004" // 删除门店消息
	StatusIDUpdateStore = "12009" // 修改门店消息
)

const (
	AfsServiceStateWaiting4Audit                = "10" // 待审核
	AfsServiceStateWaiting4UserFeedback         = "11" // 待用户反馈
	AfsServiceStateWaiting4CSFeedback           = "12" // 待客服反馈
	AfsServiceStateWaiting4GetGoods             = "20" // 待取件
	AfsServiceStateRefundProcessing             = "30" // 退款处理中
	AfsServiceStateWaiting4MerchantReceiveGoods = "31" // 待商家收货审核
	AfsServiceStateRefundSuccess                = "32" // 退款成功
	AfsServiceStateRefundFailed                 = "33" // 退款失败
	AfsServiceStateAuditRefused                 = "40" // 审核不通过-驳回
	AfsServiceStateUserCanceled                 = "50" // 客户取消
	AfsServiceStateMerchantFailedReceiveGoods   = "60" // 商家收货审核不通过
	AfsServiceStateSolved                       = "70" // 已解决
	AfsServiceStateWaiting4DirectCompensate     = "90" // 待直陪
	AfsServiceStateDirectCompensate             = "91" // 直赔
	AfsServiceStateDirectCompensateSuccess      = "92" // 直赔成功
	AfsServiceStateDirectCompensateFailed       = "93" // 直赔失败

	AfsServiceStateWaiting4ReturnGoods = "110"  // 待退货
	AfsServiceStateGetGoodsSuccess     = "111"  // 取货成功
	AfsServiceStateGettingGoods        = "1101" // 取货中
	AfsServiceStateGetGoods2Shop       = "1111" // 退货成功-商品已送至门店
	AfsServiceStateGetGoodsConfirmed   = "1112" // 退货成功-商家已确认收货

	AfsServiceStateGetGoodsWaiting4Refund = "112" // 退货成功-待退款
	AfsServiceStateReturnGoodsFailed      = "113" // 退货失败
	AfsServiceStateReturnGoodsSuccess     = "114" // 退货成功
)

const (
	// 订单
	CallbackMsgDeliveryCarrierModify       = "deliveryCarrierModify" // 订单转自送消息（是指转自送成功后，用处不大）
	CallbackMsgOrderAccounting             = "orderAccounting"       // 订单应结消息
	CallbackMsgApplyCancelOrder            = "applyCancelOrder"
	CallbackMsgPushDeliveryStatus          = "pushDeliveryStatus"
	CallbackMsgVenderAuditApplyCancelOrder = "venderAuditApplyCancelOrder"
	CallbackMsgOrderInfoChange             = "orderInfoChange" //订单售前用户改变收货地址电话等

	// 账务
	CallbackMsgEndOrderFinance   = "endOrderFinance"         // 订单金额拆分完成消息
	CallbackMsgFinanceAdjustment = "financeAdjustment"       // 财务调整单消息
	CallbackMsgApplyInvoice      = "applyOrderInvoiceStatus" // 发票消息

	// 售后
	CallbackMsgNewApplyAfterSaleBill    = "newApplyAfterSaleBill"    // 新建售后单申请消息
	CallbackMsgUpdateApplyAfterSaleBill = "updateApplyAfterSaleBill" // 修改售后单申请消息
	CallbackMsgNewAfterSaleBill         = "newAfterSaleBill"         // 新建售后单消息
	CallbackMsgAfterSaleBillStatus      = "afterSaleBillStatus"      // 售后单状态消息

	//会员
	CallBackMsgMemberCreateCard = "memberCreateCard" //会员开卡
	CallBackMsgMemberRenewCard  = "memberRenewCard"  //会员续费

	CallbackMsgOrderAddTips = "orderAddTips" // 订单商家小费消息

	CallbackMsgStockIsHave = "stockIsHave"
)

type CallbackResponse struct {
	Code string `json:"code"`
	Msg  string `json:"msg"`
	Data string `json:"data"`
}

type CallbackMsg struct {
	MsgURL string `json:"msgURL"`

	AppKey    string `json:"app_key"`
	Token     string `json:"token"`
	Timestamp string `json:"timestamp"`
	Sign      string `json:"sign"`
	Format    string `json:"format"`
	V         string `json:"v"`

	JdParamJSON string      `json:"jd_param_json"`
	Param       interface{} `json:"-"` // 这里json必须是-，否则会导致json encode时死递归
}

type CallbackOrderMsg struct {
	*CallbackMsg
	BillID    string `json:"billId"`
	OutBillID string `json:"outBillId"`
	StatusID  string `json:"statusId"`
	Timestamp string `json:"timestamp"`
	Remark    string `json:"remark"`
}

type CallbackOrderInfoChangeMsg struct {
	*CallbackMsg
	BillID                     string `json:"billId"`                     //10003129 	消息单据ID
	StatusID                   string `json:"statusId"`                   //1	不必做业务判断，与接口含义相同，表示订单消息变更(历史原因保留字段，不建议使用)
	Timestamp                  string `json:"timestamp"`                  //2015-10-16 13:23:30	日期格式为"yyyy-MM-dd HH:mm:ss"
	BuyerProvince              string `json:"buyerProvince"`              //	18	省Id（有值表示信息变更后的值）
	BuyerCity                  string `json:"buyerCity"`                  //1	市Id（有值表示信息变更后的值）
	BuyerCountry               string `json:"buyerCountry"`               //	123	县Id（有值表示信息变更后的值）
	BuyerFullAddress           string `json:"buyerFullAddress"`           //		用户地址	收货人详细地址（有值表示信息变更后的值）
	BuyerFullName              string `json:"buyerFullName"`              //	用户名	收货人名称（有值表示信息变更后的值）
	BuyerLng                   string `json:"buyerLng"`                   //1.1	收货人地址坐标纬度（有值表示信息变更后的值）
	BuyerLat                   string `json:"buyerLat"`                   //1.1	收货人地址坐标经度（有值表示信息变更后的值）
	BuyerMobile                string `json:"buyerMobile"`                //01058434049	收货人手机号（有值表示信息变更后的值）
	Midnumber                  string `json:"midnumber"`                  //01058434049	中间号（有值表示信息变更后的值）
	MiddleNumBindingTimestring string `json:"middleNumBindingTimestring"` //			2017-10-29 22:54:44	绑定中间号有效期截止时间（有值表示信息变更后的值）
	OrderBuyerRemark           string `json:"orderBuyerRemark"`           //		用户备注	订单买家备注（有值表示信息变更后的值）
}

type CallbackMemberMsg struct {
	*CallbackMsg
	Outbillid string `json:"outBillId"`
	Billid    string `json:"billId"`
	Statusid  string `json:"statusId"`
	Timestamp string `json:"timestamp"`
}

type CallbackDeliveryStatusMsg struct {
	*CallbackMsg
	OrderID             string `json:"orderId"`
	DeliveryStatusTime  string `json:"deliveryStatusTime"`
	DeliveryManNo       string `json:"deliveryManNo"`
	DeliveryManName     string `json:"deliveryManName"`
	DeliveryManPhone    string `json:"deliveryManPhone"`
	DeliveryCarrierNo   string `json:"deliveryCarrierNo"`
	DeliveryCarrierName string `json:"deliveryCarrierName"`
	DeliveryStatus      string `json:"deliveryStatus"`
	Remark              string `json:"remark"`
	FailType            string `json:"failType"`
	CreatePin           string `json:"createPin"`
	OpTime              string `json:"opTime"`
	InputTime           string `json:"inputTime"`
}

type CallbackStoreStockMsg struct {
	*CallbackMsg
	StationNo   string `json:"stationNo"`
	SkuID       int64  `json:"skuId"`
	Have        bool   `json:"have"`
	Vendibility int    `json:"vendibility"`
	OperPin     string `json:"operPin"`
	OperTime    int64  `json:"operTime"`
	OperSource  int    `json:"operSource"`
}

type CallbackInvoiceMsg struct {
	*CallbackMsg
	BillID        string `json:"billId"`        // 消息单据ID
	Id            string `json:"id"`            //	主键id
	InvoiceStatus string `json:"invoiceStatus"` // 更新后的发票状态 1:待开票 3:开票中 4:开票成功 5:开票失败 6:冲红中 7:冲红成功 8:冲红失败 9:已驳回 11:蓝票审核失败 12:红票审核失败 13:待换开 14:换开中 15:换开驳回 16:退款关闭 17:协商关闭
	Modified      string `json:"modified"`      // 发票状态更新时刻
	StoreId       string `json:"storeId"`       // 门店id（非必需，当状态变化来自秒送门店的时候才会携带）
}

const (
	OpenSourceJDLSP            = 1
	OpenSourceJDMedicineCity   = 2
	OpenSourceJDMerchantDirect = 3
	OpenSourceJDOne            = 4
	OpenSourceStockCenter      = 5
	OpenSourceOrderCenter      = 6
	OpenSourceGoodsSystem      = 7
	OpenSourcePrepositionWH    = 8
	OpenSourceStoreSystem      = 9
	OpenSourceMerchantCenter   = 10
	OpenSourceOpenPlatform     = 11
	OpenSourcePickupSystem     = 13
	OpenSourceBatchTask        = 14
)

var (
	SuccessResponse     = &CallbackResponse{Code: "0", Msg: "success", Data: ""}
	FormatErrorResponse = &CallbackResponse{Code: "-1", Msg: "failed", Data: ""}

	needDecodeMap = map[string]bool{
		CallbackMsgApplyCancelOrder:            true,
		CallbackMsgPushDeliveryStatus:          true,
		CallbackMsgStockIsHave:                 true,
		CallbackMsgVenderAuditApplyCancelOrder: true,
	}
)

func Err2CallbackResponse(err error, data string) *CallbackResponse {
	if err == nil {
		return SuccessResponse
	}
	return &CallbackResponse{
		Code: ResponseCodeFailedCanAutoRetry,
		Msg:  err.Error(),
		Data: data,
	}
}

func map2StockCallbackMsg(mapData map[string]interface{}) (msg *CallbackStoreStockMsg) {
	msg = &CallbackStoreStockMsg{
		StationNo:   utils.Interface2String(mapData["stationNo"]),
		SkuID:       utils.Str2Int64(utils.Interface2String(mapData["skuId"])),
		Vendibility: int(utils.Str2Int64(utils.Interface2String(mapData["vendibility"]))),
		OperPin:     utils.Interface2String(mapData["operPin"]),
		OperTime:    utils.Str2Int64(utils.Interface2String(mapData["operTime"])),
		OperSource:  int(utils.Str2Int64((utils.Interface2String(mapData["operSource"])))),
		Have:        utils.Interface2String(mapData["have"]) == "true",
	}
	return msg
}

func getMsgURLFromRequest(request *http.Request) (msgURL string) {
	index := strings.Index(request.URL.Path, CallbackPrefix)
	if index >= 0 {
		msgURL = request.URL.Path[index+len(CallbackPrefix):]
	}
	return msgURL
}

func GetCallbackMsg(request *http.Request) (callbackMsg *CallbackMsg, mapData map[string]interface{}, callbackResponse *CallbackResponse) {
	msgURL := getMsgURLFromRequest(request)
	data, err := ioutil.ReadAll(request.Body)
	if err != nil {
		return nil, nil, Err2CallbackResponse(err, "")
	}

	values, err := utils.HTTPBody2Values(data, needDecodeMap[msgURL])
	if err != nil {
		return nil, nil, FormatErrorResponse
	}
	mapData = utils.URLValues2Map(values)
	if err = utils.Map2StructByJson(mapData, &callbackMsg, false); err == nil {
		callbackMsg.MsgURL = msgURL
		if msgURL == CallbackMsgPushDeliveryStatus {
			var deliveryMsg *CallbackDeliveryStatusMsg
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &deliveryMsg); err == nil {
				callbackMsg.Param = deliveryMsg
				deliveryMsg.CallbackMsg = callbackMsg
			}
		} else if msgURL == CallbackMsgStockIsHave {
			var mapData map[string]interface{}
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &mapData); err == nil {
				stockMsg := map2StockCallbackMsg(mapData)
				callbackMsg.Param = stockMsg
				stockMsg.CallbackMsg = callbackMsg
			}
		} else if msgURL == CallbackMsgOrderInfoChange {
			var orderInfoMsg *CallbackOrderInfoChangeMsg
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderInfoMsg); err == nil {
				callbackMsg.Param = orderInfoMsg
				orderInfoMsg.CallbackMsg = callbackMsg
			}
		} else if msgURL == CallBackMsgMemberCreateCard || msgURL == CallBackMsgMemberRenewCard {
			var orderInfoMsg *CallbackMemberMsg
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderInfoMsg); err == nil {
				callbackMsg.Param = orderInfoMsg
				orderInfoMsg.CallbackMsg = callbackMsg
			}
		} else if msgURL == CallbackMsgApplyInvoice {
			var orderInfoMsg *CallbackInvoiceMsg
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderInfoMsg); err == nil {
				callbackMsg.Param = orderInfoMsg
				orderInfoMsg.CallbackMsg = callbackMsg
			}
			fmt.Println(orderInfoMsg)

		} else {
			var orderMsg *CallbackOrderMsg
			if err = utils.UnmarshalUseNumber([]byte(callbackMsg.JdParamJSON), &orderMsg); err == nil {
				callbackMsg.Param = orderMsg
				orderMsg.CallbackMsg = callbackMsg
			}
		}
	}

	return callbackMsg, mapData, callbackResponse
}
func (a *API) CheckCallbackValidation(mapData map[string]interface{}, signInData string) (callbackResponse *CallbackResponse) {
	sign := a.signParams(mapData)
	if sign != signInData {
		baseapi.SugarLogger.Infof("Signature is not ok, mine:%s, signInData:%s", sign, signInData)
		return FormatErrorResponse
	}
	return nil
}
