package kf

import (
	"encoding/xml"

	"github.com/silenceper/wechat/v2/util"
)

// SignatureOptions 微信服务器验证参数
type SignatureOptions struct {
	Signature string `form:"msg_signature" json:"msg_signature"`
	TimeStamp string `form:"timestamp" json:"timestamp"`
	Nonce     string `form:"nonce" json:"nonce"`
	EchoStr   string `form:"echostr" json:"echostr"`
}

// VerifyURL 验证请求参数是否合法并返回解密后的消息内容
//
//	 //Gin框架的使用示例
//		r.GET("/v1/event/callback", func(c *gin.Context) {
//			options := kf.SignatureOptions{}
//			//获取回调的的校验参数
//			if = c.ShouldBindQuery(&options); err != nil {
//				c.String(http.StatusUnauthorized, "参数解析失败")
//			}
//			// 调用VerifyURL方法校验当前请求，如果合法则把解密后的内容作为响应返回给微信服务器
//			echo, err := kfClient.VerifyURL(options)
//			if err == nil {
//				c.String(http.StatusOK, echo)
//			} else {
//				c.String(http.StatusUnauthorized, "非法请求来源")
//			}
//		})
func (r *Client) VerifyURL(options SignatureOptions) (string, error) {
	if options.Signature != util.Signature(r.ctx.Token, options.TimeStamp, options.Nonce, options.EchoStr) {
		return "", NewSDKErr(40015)
	}
	_, bData, err := util.DecryptMsg(r.corpID, options.EchoStr, r.encodingAESKey)
	if err != nil {
		return "", NewSDKErr(40016)
	}

	return string(bData), nil
}

// 原始回调消息内容
type callbackOriginMessage struct {
	ToUserName string // 企业微信的CorpID，当为第三方套件回调事件时，CorpID的内容为suiteid
	AgentID    string // 接收的应用id，可在应用的设置页面获取
	Encrypt    string // 消息结构体加密后的字符串
}

// CallbackMessage 微信客服回调消息
type CallbackMessage struct {
	ToUserName string `json:"to_user_name" xml:"ToUserName"` // 微信客服组件ID
	CreateTime int64  `json:"create_time" xml:"CreateTime"`  // 消息创建时间，unix时间戳
	MsgType    string `json:"msgtype" xml:"MsgType"`         // 消息的类型，此时固定为 event
	Event      string `json:"event" xml:"Event"`             // 事件的类型，此时固定为 kf_msg_or_event
	Token      string `json:"token" xml:"Token"`             // 调用拉取消息接口时，需要传此token，用于校验请求的合法性
	OpenKfID   string `json:"open_kfid" xml:"OpenKfId"`      // 有新消息的客服帐号。可通过sync_msg接口指定open_kfid获取此客服帐号的消息
}

// GetCallbackMessage 获取回调事件中的消息内容
//
//	 //Gin框架的使用示例
//		r.POST("/v1/event/callback", func(c *gin.Context) {
//			var (
//				message kf.CallbackMessage
//				body []byte
//			)
//			// 读取原始消息内容
//			body, err = c.GetRawData()
//			if err != nil {
//				c.String(http.StatusInternalServerError, err.Error())
//				return
//			}
//			// 解析原始数据
//			message, err = kfClient.GetCallbackMessage(body)
//			if err != nil {
//				c.String(http.StatusInternalServerError, "消息获取失败")
//				return
//			}
//			fmt.Println(message)
//			c.String(200, "ok")
//		})
func (r *Client) GetCallbackMessage(encryptedMsg []byte) (msg CallbackMessage, err error) {
	var origin callbackOriginMessage
	if err = xml.Unmarshal(encryptedMsg, &origin); err != nil {
		return msg, err
	}
	_, bData, err := util.DecryptMsg(r.corpID, origin.Encrypt, r.encodingAESKey)
	if err != nil {
		return msg, NewSDKErr(40016)
	}
	err = xml.Unmarshal(bData, &msg)
	return msg, err
}
