package message

import (
	"encoding/json"
	"encoding/xml"
	"errors"
	"io"
	"net/http"
	"sort"
	"strings"

	"github.com/tidwall/gjson"

	"github.com/silenceper/wechat/v2/miniprogram/context"
	"github.com/silenceper/wechat/v2/miniprogram/security"
	"github.com/silenceper/wechat/v2/util"
)

// ConfirmReceiveMethod 确认收货方式
type ConfirmReceiveMethod int8

const (
	// EventTypeTradeManageRemindAccessAPI 提醒接入发货信息管理服务 API
	// 小程序完成账期授权时/小程序产生第一笔交易时/已产生交易但从未发货的小程序，每天一次
	EventTypeTradeManageRemindAccessAPI EventType = "trade_manage_remind_access_api"
	// EventTypeTradeManageRemindShipping 提醒需要上传发货信息
	// 曾经发过货的小程序，订单超过 48 小时未发货时
	EventTypeTradeManageRemindShipping EventType = "trade_manage_remind_shipping"
	// EventTypeTradeManageOrderSettlement 订单将要结算或已经结算
	// 订单完成发货时/订单结算时
	EventTypeTradeManageOrderSettlement EventType = "trade_manage_order_settlement"
	// EventTypeAddExpressPath 运单轨迹更新事件
	EventTypeAddExpressPath EventType = "add_express_path"
	// EventTypeSecvodUpload 短剧媒资上传完成事件
	EventTypeSecvodUpload EventType = "secvod_upload_event"
	// EventTypeSecvodAudit 短剧媒资审核状态事件
	EventTypeSecvodAudit EventType = "secvod_audit_event"
	// EventTypeWxaMediaCheck 媒体内容安全异步审查结果通知
	EventTypeWxaMediaCheck EventType = "wxa_media_check"
	// EventTypeXpayGoodsDeliverNotify 道具发货推送事件
	EventTypeXpayGoodsDeliverNotify EventType = "xpay_goods_deliver_notify"
	// EventTypeXpayCoinPayNotify 代币支付推送事件
	EventTypeXpayCoinPayNotify EventType = "xpay_coin_pay_notify"
	// EventTypeXpayRefundNotify 退款推送事件
	EventTypeXpayRefundNotify EventType = "xpay_refund_notify"
	// EventTypeXpaySubscribeIosRefundQueryNotify iOS Apple 支付退款问询事件
	EventTypeXpaySubscribeIosRefundQueryNotify EventType = "xpay_subscribe_ios_refund_query_notify"
	// EventTypeXpayComplaintNotify 用户投诉推送事件
	EventTypeXpayComplaintNotify EventType = "xpay_complaint_notify"
	// EventSubscribePopup 用户操作订阅通知弹窗事件推送，用户在图文等场景内订阅通知的操作
	EventSubscribePopup EventType = "subscribe_msg_popup_event"
	// EventSubscribeMsgChange 用户管理订阅通知，用户在服务通知管理页面做通知管理时的操作
	EventSubscribeMsgChange EventType = "subscribe_msg_change_event"
	// EventSubscribeMsgSent 发送订阅通知，调用 bizsend 接口发送通知
	EventSubscribeMsgSent EventType = "subscribe_msg_sent_event"
	// ConfirmReceiveMethodAuto 自动确认收货
	ConfirmReceiveMethodAuto ConfirmReceiveMethod = 1
	// ConfirmReceiveMethodManual 手动确认收货
	ConfirmReceiveMethodManual ConfirmReceiveMethod = 2
)

const (
	// InfoTypeAcceptSubscribeMessage 接受订阅通知
	InfoTypeAcceptSubscribeMessage InfoType = "accept"
	// InfoTypeRejectSubscribeMessage 拒绝订阅通知
	InfoTypeRejectSubscribeMessage InfoType = "reject"
)

// PushReceiver 接收消息推送
// 暂仅支付 Aes 加密方式
type PushReceiver struct {
	*context.Context
}

// NewPushReceiver 实例化
func NewPushReceiver(ctx *context.Context) *PushReceiver {
	return &PushReceiver{
		Context: ctx,
	}
}

// GetMsg 获取接收到的消息 (如果是加密的返回解密数据)
func (receiver *PushReceiver) GetMsg(r *http.Request) (string, []byte, error) {
	// 判断请求格式
	var dataType string
	contentType := r.Header.Get("Content-Type")
	if strings.HasPrefix(contentType, "text/xml") {
		// xml 格式
		dataType = DataTypeXML
	} else {
		// json 格式
		dataType = DataTypeJSON
	}

	// 读取参数，验证签名
	signature := r.FormValue("signature")
	timestamp := r.FormValue("timestamp")
	nonce := r.FormValue("nonce")
	encryptType := r.FormValue("encrypt_type")
	// 验证签名
	tmpArr := []string{
		receiver.Token,
		timestamp,
		nonce,
	}
	sort.Strings(tmpArr)
	tmpSignature := util.Signature(tmpArr...)
	if tmpSignature != signature {
		return dataType, nil, errors.New("signature error")
	}

	if encryptType == "aes" {
		// 解密
		var reqData DataReceived
		if dataType == DataTypeXML {
			if err := xml.NewDecoder(r.Body).Decode(&reqData); err != nil {
				return dataType, nil, err
			}
		} else {
			if err := json.NewDecoder(r.Body).Decode(&reqData); err != nil {
				return dataType, nil, err
			}
		}
		_, rawMsgBytes, err := util.DecryptMsg(receiver.AppID, reqData.Encrypt, receiver.EncodingAESKey)
		return dataType, rawMsgBytes, err
	}
	// 不加密
	byteData, err := io.ReadAll(r.Body)
	return dataType, byteData, err
}

// GetMsgData 获取接收到的消息 (解密数据)
func (receiver *PushReceiver) GetMsgData(r *http.Request) (MsgType, EventType, PushData, error) {
	dataType, decryptMsg, err := receiver.GetMsg(r)
	if err != nil {
		return "", "", nil, err
	}
	var (
		msgType   MsgType
		eventType EventType
	)
	if dataType == DataTypeXML {
		var commonToken CommonPushData
		if err := xml.Unmarshal(decryptMsg, &commonToken); err != nil {
			return "", "", nil, err
		}
		msgType, eventType = commonToken.MsgType, commonToken.Event
	} else {
		var commonToken CommonPushData
		if err := json.Unmarshal(decryptMsg, &commonToken); err != nil {
			return "", "", nil, err
		}
		msgType, eventType = commonToken.MsgType, commonToken.Event
	}
	if msgType == MsgTypeEvent {
		pushData, err := receiver.getEvent(dataType, eventType, decryptMsg)
		// 暂不支持其他事件类型
		return msgType, eventType, pushData, err
	}
	// 暂不支持其他消息类型
	return msgType, eventType, decryptMsg, nil
}

// getEvent 获取事件推送的数据
func (receiver *PushReceiver) getEvent(dataType string, eventType EventType, decryptMsg []byte) (PushData, error) {
	switch eventType {
	case EventTypeTradeManageRemindAccessAPI:
		// 提醒接入发货信息管理服务 API
		var pushData PushDataRemindAccessAPI
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeTradeManageRemindShipping:
		// 提醒需要上传发货信息
		var pushData PushDataRemindShipping
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeTradeManageOrderSettlement:
		// 订单将要结算或已经结算
		var pushData PushDataOrderSettlement
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeWxaMediaCheck:
		// 媒体内容安全异步审查结果通知
		var pushData MediaCheckAsyncData
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeAddExpressPath:
		// 运单轨迹更新
		var pushData PushDataAddExpressPath
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeSecvodUpload:
		// 短剧媒资上传完成
		var pushData PushDataSecVodUpload
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeSecvodAudit:
		// 短剧媒资审核状态
		var pushData PushDataSecVodAudit
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeXpayGoodsDeliverNotify:
		// 道具发货推送事件
		var pushData PushDataXpayGoodsDeliverNotify
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeXpayCoinPayNotify:
		// 代币支付推送事件
		var pushData PushDataXpayCoinPayNotify
		err := receiver.unmarshal(dataType, decryptMsg, &pushData)
		return &pushData, err
	case EventTypeXpayRefundNotify:
		// 退款推送事件
		return receiver.unmarshalPushData(dataType, decryptMsg, &PushDataXpayRefundNotify{})
	case EventTypeXpaySubscribeIosRefundQueryNotify: // iOS Apple 支付退款问询事件
		return receiver.unmarshalPushData(dataType, decryptMsg, &PushDataXpaySubscribeIosRefundQueryNotify{})
	case EventTypeXpayComplaintNotify:
		// 用户投诉推送事件
		return receiver.unmarshalPushData(dataType, decryptMsg, &PushDataXpayComplaintNotify{})
	case EventSubscribePopup:
		// 用户操作订阅通知弹窗事件推送
		return receiver.unmarshalSubscribePopup(dataType, decryptMsg)
	case EventSubscribeMsgChange:
		// 用户管理订阅通知事件推送
		return receiver.unmarshalSubscribeMsgChange(dataType, decryptMsg)
	case EventSubscribeMsgSent:
		// 用户发送订阅通知事件推送
		return receiver.unmarshalSubscribeMsgSent(dataType, decryptMsg)
	}
	// 暂不支持其他事件类型，直接返回解密后的数据，由调用方处理
	return decryptMsg, nil
}

// unmarshal 解析推送的数据
func (receiver *PushReceiver) unmarshal(dataType string, decryptMsg []byte, pushData interface{}) error {
	if dataType == DataTypeXML {
		return xml.Unmarshal(decryptMsg, pushData)
	}
	return json.Unmarshal(decryptMsg, pushData)
}

// unmarshalPushData unmarshal push data helper
func (receiver *PushReceiver) unmarshalPushData(dataType string, decryptMsg []byte, pushData interface{}) (PushData, error) {
	err := receiver.unmarshal(dataType, decryptMsg, pushData)
	return pushData, err
}

// unmarshalSubscribePopup
func (receiver *PushReceiver) unmarshalSubscribePopup(dataType string, decryptMsg []byte) (PushData, error) {
	var pushData PushDataSubscribePopup
	err := receiver.unmarshal(dataType, decryptMsg, &pushData)
	if err == nil {
		listData := gjson.Get(string(decryptMsg), "List")
		if listData.IsObject() {
			listItem := SubscribeMsgPopupEventList{}
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgPopupEvents([]SubscribeMsgPopupEventList{listItem})
		} else if listData.IsArray() {
			listItems := make([]SubscribeMsgPopupEventList, 0)
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgPopupEvents(listItems)
		}
	}

	return &pushData, err
}

// unmarshalSubscribeMsgChange 解析用户管理订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgChange(dataType string, decryptMsg []byte) (PushData, error) {
	var pushData PushDataSubscribeMsgChange
	err := receiver.unmarshal(dataType, decryptMsg, &pushData)
	if err == nil {
		listData := gjson.Get(string(decryptMsg), "List")
		if listData.IsObject() {
			listItem := SubscribeMsgChangeList{}
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgChangeEvents([]SubscribeMsgChangeList{listItem})
		} else if listData.IsArray() {
			listItems := make([]SubscribeMsgChangeList, 0)
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgChangeEvents(listItems)
		}
	}
	return &pushData, err
}

// unmarshalSubscribeMsgSent 解析用户发送订阅通知事件推送
func (receiver *PushReceiver) unmarshalSubscribeMsgSent(dataType string, decryptMsg []byte) (PushData, error) {
	var pushData PushDataSubscribeMsgSent
	err := receiver.unmarshal(dataType, decryptMsg, &pushData)
	if err == nil {
		listData := gjson.Get(string(decryptMsg), "List")
		if listData.IsObject() {
			listItem := SubscribeMsgSentList{}
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItem); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgSentEvents([]SubscribeMsgSentList{listItem})
		} else if listData.IsArray() {
			listItems := make([]SubscribeMsgSentList, 0)
			if parseErr := json.Unmarshal([]byte(listData.Raw), &listItems); parseErr != nil {
				return &pushData, parseErr
			}
			pushData.SetSubscribeMsgSentEvents(listItems)
		}
	}
	return &pushData, err
}

// DataReceived 接收到的数据
type DataReceived struct {
	Encrypt string `json:"Encrypt" xml:"Encrypt"` // 加密的消息体
}

// PushData 推送的数据 (已转对应的结构体)
type PushData interface{}

// CommonPushData 推送数据通用部分
type CommonPushData struct {
	XMLName      xml.Name  `json:"-" xml:"xml"`
	MsgType      MsgType   `json:"MsgType" xml:"MsgType"`           // 消息类型，为固定值 "event"
	Event        EventType `json:"Event" xml:"Event"`               // 事件类型
	ToUserName   string    `json:"ToUserName" xml:"ToUserName"`     // 小程序的原始 ID
	FromUserName string    `json:"FromUserName" xml:"FromUserName"` // 发送方账号（一个 OpenID，此时发送方是系统账号）
	CreateTime   int64     `json:"CreateTime" xml:"CreateTime"`     // 消息创建时间（整型），时间戳
}

// MediaCheckAsyncData 媒体内容安全异步审查结果通知
type MediaCheckAsyncData struct {
	CommonPushData
	Appid   string                `json:"appid" xml:"appid"`
	TraceID string                `json:"trace_id" xml:"trace_id"`
	Version int                   `json:"version" xml:"version"`
	Detail  []*MediaCheckDetail   `json:"detail" xml:"detail"`
	Errcode int                   `json:"errcode" xml:"errcode"`
	Errmsg  string                `json:"errmsg" xml:"errmsg"`
	Result  MediaCheckAsyncResult `json:"result" xml:"result"`
}

// MediaCheckDetail 检测结果详情
type MediaCheckDetail struct {
	Strategy string                `json:"strategy" xml:"strategy"`
	Errcode  int                   `json:"errcode" xml:"errcode"`
	Suggest  security.CheckSuggest `json:"suggest" xml:"suggest"`
	Label    int                   `json:"label" xml:"label"`
	Prob     int                   `json:"prob" xml:"prob"`
}

// MediaCheckAsyncResult 检测结果
type MediaCheckAsyncResult struct {
	Suggest security.CheckSuggest `json:"suggest" xml:"suggest"`
	Label   security.CheckLabel   `json:"label" xml:"label"`
}

// PushDataOrderSettlement 订单将要结算或已经结算通知
type PushDataOrderSettlement struct {
	CommonPushData
	TransactionID           string               `json:"transaction_id" xml:"transaction_id"`                       // 支付订单号
	MerchantID              string               `json:"merchant_id" xml:"merchant_id"`                             // 商户号
	SubMerchantID           string               `json:"sub_merchant_id" xml:"sub_merchant_id"`                     // 子商户号
	MerchantTradeNo         string               `json:"merchant_trade_no" xml:"merchant_trade_no"`                 // 商户订单号
	PayTime                 int64                `json:"pay_time" xml:"pay_time"`                                   // 支付成功时间，秒级时间戳
	ShippedTime             int64                `json:"shipped_time" xml:"shipped_time"`                           // 发货时间，秒级时间戳
	EstimatedSettlementTime int64                `json:"estimated_settlement_time" xml:"estimated_settlement_time"` // 预计结算时间，秒级时间戳。发货时推送才有该字段
	ConfirmReceiveMethod    ConfirmReceiveMethod `json:"confirm_receive_method" xml:"confirm_receive_method"`       // 确认收货方式：1. 自动确认收货；2. 手动确认收货。结算时推送才有该字段
	ConfirmReceiveTime      int64                `json:"confirm_receive_time" xml:"confirm_receive_time"`           // 确认收货时间，秒级时间戳。结算时推送才有该字段
	SettlementTime          int64                `json:"settlement_time" xml:"settlement_time"`                     // 订单结算时间，秒级时间戳。结算时推送才有该字段
}

// PushDataRemindShipping 提醒需要上传发货信息
type PushDataRemindShipping struct {
	CommonPushData
	TransactionID   string `json:"transaction_id" xml:"transaction_id"`       // 微信支付订单号
	MerchantID      string `json:"merchant_id" xml:"merchant_id"`             // 商户号
	SubMerchantID   string `json:"sub_merchant_id" xml:"sub_merchant_id"`     // 子商户号
	MerchantTradeNo string `json:"merchant_trade_no" xml:"merchant_trade_no"` // 商户订单号
	PayTime         int64  `json:"pay_time" xml:"pay_time"`                   // 支付成功时间，秒级时间戳
	Msg             string `json:"msg" xml:"msg"`                             // 消息文本内容
}

// PushDataRemindAccessAPI 提醒接入发货信息管理服务 API 信息
type PushDataRemindAccessAPI struct {
	CommonPushData
	Msg string `json:"msg" xml:"msg"` // 消息文本内容
}

// PushDataAddExpressPath 运单轨迹更新信息
type PushDataAddExpressPath struct {
	CommonPushData
	DeliveryID string                          `json:"DeliveryID" xml:"DeliveryID"` // 快递公司 ID
	WayBillID  string                          `json:"WaybillId" xml:"WaybillId"`   // 运单 ID
	OrderID    string                          `json:"OrderId" xml:"OrderId"`       // 订单 ID
	Version    int                             `json:"Version" xml:"Version"`       // 轨迹版本号（整型）
	Count      int                             `json:"Count" xml:"Count"`           // 轨迹节点数（整型）
	Actions    []*PushDataAddExpressPathAction `json:"Actions" xml:"Actions"`       // 轨迹节点列表
}

// PushDataAddExpressPathAction 轨迹节点
type PushDataAddExpressPathAction struct {
	ActionTime int64  `json:"ActionTime" xml:"ActionTime"` // 轨迹节点 Unix 时间戳
	ActionType int    `json:"ActionType" xml:"ActionType"` // 轨迹节点类型
	ActionMsg  string `json:"ActionMsg" xml:"ActionMsg"`   // 轨迹节点详情
}

// PushDataSecVodUpload 短剧媒资上传完成
type PushDataSecVodUpload struct {
	CommonPushData
	UploadEvent SecVodUploadEvent `json:"upload_event" xml:"upload_event"` // 上传完成事件
}

// SecVodUploadEvent 短剧媒资上传完成事件
type SecVodUploadEvent struct {
	MediaID       int64  `json:"media_id" xml:"media_id"`             // 媒资 id
	SourceContext string `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值。
	ErrCode       int    `json:"errcode" xml:"errcode"`               // 错误码，上传失败时该值非
	ErrMsg        string `json:"errmsg" xml:"errmsg"`                 // 错误提示
}

// PushDataSecVodAudit 短剧媒资审核状态
type PushDataSecVodAudit struct {
	CommonPushData
	AuditEvent SecVodAuditEvent `json:"audit_event" xml:"audit_event"` // 审核状态事件
}

// SecVodAuditEvent 短剧媒资审核状态事件
type SecVodAuditEvent struct {
	DramaID       int64            `json:"drama_id" xml:"drama_id"`             // 剧目 id
	SourceContext string           `json:"source_context" xml:"source_context"` // 透传上传接口中开发者设置的值
	AuditDetail   DramaAuditDetail `json:"audit_detail" xml:"audit_detail"`     // 剧目审核结果，单独每一集的审核结果可以根据 drama_id 查询剧集详情得到
}

// DramaAuditDetail 剧目审核结果
type DramaAuditDetail struct {
	Status     int   `json:"status" xml:"status"`           // 审核状态，0 为无效值；1 为审核中；2 为最终失败；3 为审核通过；4 为驳回重填
	CreateTime int64 `json:"create_time" xml:"create_time"` // 提审时间戳
	AuditTime  int64 `json:"audit_time" xml:"audit_time"`   // 审核时间戳
}

// PushDataXpayGoodsDeliverNotify 道具发货推送
type PushDataXpayGoodsDeliverNotify struct {
	CommonPushData
	OpenID        string        `json:"OpenId" xml:"OpenId"`               // 用户 openid
	OutTradeNo    string        `json:"OutTradeNo" xml:"OutTradeNo"`       // 业务订单号
	Env           int           `json:"Env" xml:"Env"`                     // ，环境配置 0：现网环境（也叫正式环境）1：沙箱环境
	WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
	GoodsInfo     GoodsInfo     `json:"GoodsInfo" xml:"GoodsInfo"`         // 道具参数信息
	TeamInfo      XpayTeamInfo  `json:"TeamInfo" xml:"TeamInfo"`           // 拼团信息
}

// WeChatPayInfo 微信支付信息
type WeChatPayInfo struct {
	MchOrderNo    string `json:"MchOrderNo" xml:"MchOrderNo"`       // 微信支付商户单号
	TransactionID string `json:"TransactionId" xml:"TransactionId"` // 交易单号（微信支付订单号）
	PaidTime      int64  `json:"PaidTime" xml:"PaidTime"`           // 用户支付时间，Linux 秒级时间戳
}

// GoodsInfo 道具参数信息
type GoodsInfo struct {
	ProductID   string `json:"ProductId" xml:"ProductId"`     // 道具 ID
	Quantity    int    `json:"Quantity" xml:"Quantity"`       // 数量
	OrigPrice   int64  `json:"OrigPrice" xml:"OrigPrice"`     // 物品原始价格（单位：分）
	ActualPrice int64  `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格（单位：分）
	Attach      string `json:"Attach" xml:"Attach"`           // 透传信息
}

// PushDataXpayCoinPayNotify 代币支付推送
type PushDataXpayCoinPayNotify struct {
	CommonPushData
	OpenID        string        `json:"OpenId" xml:"OpenId"`               // 用户 openid
	OutTradeNo    string        `json:"OutTradeNo" xml:"OutTradeNo"`       // 业务订单号
	Env           int           `json:"Env" xml:"Env"`                     // ，环境配置 0：现网环境（也叫正式环境）1：沙箱环境
	WeChatPayInfo WeChatPayInfo `json:"WeChatPayInfo" xml:"WeChatPayInfo"` // 微信支付信息 非微信支付渠道可能没有
	CoinInfo      CoinInfo      `json:"CoinInfo" xml:"CoinInfo"`           // 代币参数信息
}

// CoinInfo 代币参数信息
type CoinInfo struct {
	Quantity    int    `json:"Quantity" xml:"Quantity"`       // 数量
	OrigPrice   int64  `json:"OrigPrice" xml:"OrigPrice"`     // 物品原始价格（单位：分）
	ActualPrice int64  `json:"ActualPrice" xml:"ActualPrice"` // 物品实际支付价格（单位：分）
	Attach      string `json:"Attach" xml:"Attach"`           // 透传信息
}

// PushDataSubscribePopup 用户操作订阅通知弹窗事件推送
type PushDataSubscribePopup struct {
	CommonPushData
	subscribeMsgPopupEventList []SubscribeMsgPopupEventList `json:"-"`
	SubscribeMsgPopupEvent     SubscribeMsgPopupEvent       `xml:"SubscribeMsgPopupEvent"`
}

// SubscribeMsgPopupEvent 用户操作订阅通知弹窗消息回调
type SubscribeMsgPopupEvent struct {
	List []SubscribeMsgPopupEventList `xml:"List"`
}

// SubscribeMsgPopupEventList 订阅消息事件列表
type SubscribeMsgPopupEventList struct {
	TemplateID            string `xml:"TemplateId" json:"TemplateId"`
	SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
	PopupScene            string `xml:"PopupScene" json:"PopupScene"`
}

// SetSubscribeMsgPopupEvents 设置订阅消息事件
func (s *PushDataSubscribePopup) SetSubscribeMsgPopupEvents(list []SubscribeMsgPopupEventList) {
	s.subscribeMsgPopupEventList = list
}

// GetSubscribeMsgPopupEvents 获取订阅消息事件数据
func (s *PushDataSubscribePopup) GetSubscribeMsgPopupEvents() []SubscribeMsgPopupEventList {
	if s.subscribeMsgPopupEventList != nil {
		return s.subscribeMsgPopupEventList
	}

	if s.SubscribeMsgPopupEvent.List == nil || len(s.SubscribeMsgPopupEvent.List) < 1 {
		return nil
	}
	return s.SubscribeMsgPopupEvent.List
}

// PushDataSubscribeMsgChange 用户管理订阅通知事件推送
type PushDataSubscribeMsgChange struct {
	CommonPushData
	SubscribeMsgChangeEvent SubscribeMsgChangeEvent  `xml:"SubscribeMsgChangeEvent"`
	subscribeMsgChangeList  []SubscribeMsgChangeList `json:"-"`
}

// SubscribeMsgChangeEvent 用户管理订阅通知回调
type SubscribeMsgChangeEvent struct {
	List []SubscribeMsgChangeList `xml:"List" json:"List"`
}

// SubscribeMsgChangeList 订阅消息事件列表
type SubscribeMsgChangeList struct {
	TemplateID            string `xml:"TemplateId" json:"TemplateId"`
	SubscribeStatusString string `xml:"SubscribeStatusString" json:"SubscribeStatusString"`
}

// SetSubscribeMsgChangeEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgChange) SetSubscribeMsgChangeEvents(list []SubscribeMsgChangeList) {
	s.subscribeMsgChangeList = list
}

// GetSubscribeMsgChangeEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgChange) GetSubscribeMsgChangeEvents() []SubscribeMsgChangeList {
	if s.subscribeMsgChangeList != nil {
		return s.subscribeMsgChangeList
	}

	if s.SubscribeMsgChangeEvent.List == nil || len(s.SubscribeMsgChangeEvent.List) < 1 {
		return nil
	}

	return s.SubscribeMsgChangeEvent.List
}

// PushDataSubscribeMsgSent 用户发送订阅通知事件推送
type PushDataSubscribeMsgSent struct {
	CommonPushData
	SubscribeMsgSentEvent     SubscribeMsgSentEvent  `xml:"SubscribeMsgSentEvent"`
	subscribeMsgSentEventList []SubscribeMsgSentList `json:"-"`
}

// SubscribeMsgSentEvent 用户发送订阅通知回调
type SubscribeMsgSentEvent struct {
	List []SubscribeMsgSentList `xml:"List" json:"List"`
}

// SubscribeMsgSentList 订阅消息事件列表
type SubscribeMsgSentList struct {
	TemplateID  string `xml:"TemplateId" json:"TemplateId"`
	MsgID       string `xml:"MsgID" json:"MsgID"`
	ErrorCode   string `xml:"ErrorCode" json:"ErrorCode"`
	ErrorStatus string `xml:"ErrorStatus" json:"ErrorStatus"`
}

// SetSubscribeMsgSentEvents 设置订阅消息事件
func (s *PushDataSubscribeMsgSent) SetSubscribeMsgSentEvents(list []SubscribeMsgSentList) {
	s.subscribeMsgSentEventList = list
}

// GetSubscribeMsgSentEvents 获取订阅消息事件数据
func (s *PushDataSubscribeMsgSent) GetSubscribeMsgSentEvents() []SubscribeMsgSentList {
	if s.subscribeMsgSentEventList != nil {
		return s.subscribeMsgSentEventList
	}

	if s.SubscribeMsgSentEvent.List == nil || len(s.SubscribeMsgSentEvent.List) < 1 {
		return nil
	}

	return s.SubscribeMsgSentEvent.List
}

// XpayTeamInfo team purchase info
type XpayTeamInfo struct {
	ActivityID string `json:"ActivityId" xml:"ActivityId"` // 活动 id
	TeamID     string `json:"TeamId" xml:"TeamId"`         // 团 id
	TeamType   int    `json:"TeamType" xml:"TeamType"`     // 团类型 1-支付全部，拼成退款
	TeamAction int    `json:"TeamAction" xml:"TeamAction"` // 0-创团 1-参团
}

// PushDataXpayRefundNotify 退款推送
type PushDataXpayRefundNotify struct {
	CommonPushData
	OpenID                   string       `json:"OpenId" xml:"OpenId"`                                     // 用户 openid
	WxRefundID               string       `json:"WxRefundId" xml:"WxRefundId"`                             // 微信退款单号
	MchRefundID              string       `json:"MchRefundId" xml:"MchRefundId"`                           // 商户退款单号
	WxOrderID                string       `json:"WxOrderId" xml:"WxOrderId"`                               // 退款单对应支付单的微信单号
	MchOrderID               string       `json:"MchOrderId" xml:"MchOrderId"`                             // 退款单对应支付单的商户单号
	RefundFee                int          `json:"RefundFee" xml:"RefundFee"`                               // 退款金额，单位分
	RetCode                  int          `json:"RetCode" xml:"RetCode"`                                   // 退款结果，0 为成功
	RetMsg                   string       `json:"RetMsg" xml:"RetMsg"`                                     // 退款结果详情
	RefundStartTimestamp     int64        `json:"RefundStartTimestamp" xml:"RefundStartTimestamp"`         // 开始退款时间，秒级时间戳
	RefundSuccTimestamp      int64        `json:"RefundSuccTimestamp" xml:"RefundSuccTimestamp"`           // 结束退款时间，秒级时间戳
	WxpayRefundTransactionID string       `json:"WxpayRefundTransactionId" xml:"WxpayRefundTransactionId"` // 退款单的微信支付单号
	RetryTimes               int          `json:"RetryTimes" xml:"RetryTimes"`                             // 重试次数，从 0 开始
	TeamInfo                 XpayTeamInfo `json:"TeamInfo" xml:"TeamInfo"`                                 // 拼团信息
}

// PushDataXpaySubscribeIosRefundQueryNotify iOS Apple 支付退款问询事件
// 文档：https://developers.weixin.qq.com/miniprogram/dev/platform-capabilities/business-capabilities/virtual-payment/ios.html
type PushDataXpaySubscribeIosRefundQueryNotify struct {
	CommonPushData
	RefundTime          string `json:"refund_time" xml:"refund_time"`                     // 问询时间，Unix 时间戳
	OrderTime           string `json:"order_time" xml:"order_time"`                       // 该笔退款的订单时间，Unix 时间戳
	ChannelBill         string `json:"channel_bill" xml:"channel_bill"`                   // Apple 支付票据号
	BundleID            string `json:"bundleid" xml:"bundleid"`                           // 应用的 Apple bundleid
	ProductID           string `json:"product_id" xml:"product_id"`                       // 道具 id
	PCount              string `json:"p_count" xml:"p_count"`                             // 道具/代币数量
	RefundRequestReason string `json:"refund_request_reason" xml:"refund_request_reason"` // 用户请求退款的原因
	ProvideStatus       string `json:"provide_status" xml:"provide_status"`               // 发货状态，0：未发货 1：已发货 2：发货中
	PayOrderID          string `json:"pay_order_id" xml:"pay_order_id"`                   // 退款对应支付订单号
}

// IosRefundQueryResponse iOS Apple 支付退款问询应答
type IosRefundQueryResponse struct {
	ResultCode int32  `json:"result_code" xml:"result_code"` // 结果码，0-放过，建议退款；1-拦截，拒绝退款
	ResultInfo string `json:"result_info" xml:"result_info"` // 结果描述
	Evidence   string `json:"evidence" xml:"evidence"`       // 决策凭据，必填，用于退款审计
}

// PushDataXpayComplaintNotify 用户投诉推送
type PushDataXpayComplaintNotify struct {
	CommonPushData
	OpenID          string `json:"OpenId" xml:"OpenId"`                   // 用户 openid
	WxOrderID       string `json:"WxOrderId" xml:"WxOrderId"`             // 微信单号
	MchOrderID      string `json:"MchOrderId" xml:"MchOrderId"`           // 商户单号
	TransactionID   string `json:"TransactionId" xml:"TransactionId"`     // 微信支付交易单号
	ComplaintID     string `json:"ComplaintId" xml:"ComplaintId"`         // 投诉单号
	ComplaintDetail string `json:"ComplaintDetail" xml:"ComplaintDetail"` // 投诉详情
	ComplaintTime   int64  `json:"ComplaintTime" xml:"ComplaintTime"`     // 投诉时间，秒级时间戳
	RetryTimes      int    `json:"RetryTimes" xml:"RetryTimes"`           // 重试次数，从 0 开始
	RequestID       string `json:"RequestId" xml:"RequestId"`             // 请求编号
}
