package core

import (
	"bytes"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/goWxHook/goWxHook/utils"
	"github.com/goWxHook/goWxHook/utils/json"
	"io"
	"log/slog"
	"net/http"
	"strconv"
	"time"
)

var (

	// ReportClientConnecFunc 客户连接
	ReportClientConnecFunc func(id string)
	// ReportClientCloseFunc 客户关闭
	ReportClientCloseFunc func(id string)
	// ReportClientMsgFunc 收到消息
	ReportClientMsgFunc func(id string, data string)

	// wxInitiativeCallQueue 主动消息队列
	// key: 消息id
	wxInitiativeCallQueue = utils.NewSafeMap[int, *wxCallQueue]()

	registerPid = make(map[int]bool)
)

// 每种消息类型的主动消息队列
type wxCallQueue struct {
	Send chan string // 是否有消息等待投递
	Resp chan string // 应答消息
}

func registerWxCallBackListen(port int) error {
	gin.SetMode(gin.ReleaseMode)
	callback := gin.New()
	callback.Use(gin.Recovery())
	callback.POST("/send/error", func(c *gin.Context) {
		data, _ := io.ReadAll(c.Request.Body)
		lastErrorStr = string(data)
	})
	// 客户端上报（被动消息）
	clientGroup := callback.Group("/report/client")
	{
		clientGroup.GET("/connect", reportClientConnect)
		clientGroup.GET("/close", reportClientClose)
		clientGroup.POST("/msg", reportClientMsg)
		clientGroup.POST("/log", reportTest)
	}
	slog.Info(fmt.Sprintf("启动微信回调接收监听 :%d", port))
	return callback.Run(fmt.Sprintf(":%d", port))
}

func RegisterClientConnectFunc(f func(id string)) {
	ReportClientConnecFunc = f
}

func reportTest(c *gin.Context) {
	id, _ := strconv.Atoi(c.Query("id"))
	data, _ := io.ReadAll(c.Request.Body)
	defer c.Request.Body.Close()
	slog.Debug("test log", "id", id, "data", string(data))
}

func reportClientConnect(c *gin.Context) {
	id := c.Query("id")
	if ReportClientConnecFunc != nil {
		ReportClientConnecFunc(id)
	}
}

func RegisterClientCloseFunc(f func(id string)) {
	ReportClientCloseFunc = f
}

func reportClientClose(c *gin.Context) {
	id := c.Query("id")
	if ReportClientCloseFunc != nil {
		ReportClientCloseFunc(id)
	}
}

func registerClientMsgFunc(f func(id string, data string)) {
	ReportClientMsgFunc = f
}

type wxRespDataSimple struct {
	Type int `json:"type"`
}

func reportClientMsg(c *gin.Context) {
	defer c.Request.Body.Close()
	id := c.Query("id")
	data, _ := io.ReadAll(c.Request.Body)
	// 拦截解析主动消息
	var respData wxRespDataSimple
	_ = json.Unmarshal(data, &respData)
	if respData.Type != 0 {
		// 检查主动消息
		if v, ok := wxInitiativeCallQueue.Get(respData.Type); ok {
			if respData.Type == loginSuccessMsg {
				sr := WxLoginInfoResp{}
				_ = json.Unmarshal(data, &sr)
				if _, isexits := registerPid[sr.Data.Pid]; !isexits {
					select {
					case message, ifSubscribe := <-v.Send:
						if ifSubscribe {
							v.Resp <- string(data)
							_ = message
							return
						}
					}
				}
			} else {
				select {
				case message, ifSubscribe := <-v.Send:
					if ifSubscribe {
						v.Resp <- string(data)
						_ = message
						return
					}
				}
			}

		}
	}
	// 无订阅, 进入用户回调
	dataStr := string(data)
	if ReportClientMsgFunc != nil {
		ReportClientMsgFunc(id, dataStr)
	}
}

type HttpCallBackRequest struct {
	Url     string `json:"url"`
	Timeout int    `json:"timeout"` // 默认5秒
}

// RegisterHttpCallback 注册http消息回调
func RegisterHttpCallback(url string, timeout int) error {
	if len(url) == 0 {
		return errors.New("url不能为空")
	}
	if timeout == 0 {
		timeout = 5
	}
	if timeout > 60 {
		timeout = 60
	}
	registerClientMsgFunc(func(id string, data string) {
		debugOutput(data)
		// 注册http post回调
		client := http.Client{
			Timeout: time.Duration(timeout) * time.Second,
		}
		_, err := client.Post(url, "application/json", io.NopCloser(bytes.NewBufferString(data)))
		if err != nil {
			slog.Error("RegisterHttpCallback: http post error", "url", url, "error", err)
			return
		}
	})
	return nil
}
