package api

import (
	"encoding/json"
	"errors"
	"time"

	"github.com/gookit/event"
	"github.com/gorilla/websocket"
	jsoniter "github.com/json-iterator/go"
	"github.com/sirupsen/logrus"
	"github.com/spf13/viper"
	"gogs.daxia.dev/huanan/pkg.daxia.dev/webutils"
	"nn.daxia.dev/model"
)

type Resp struct {
	Once string      `json:"once"`
	Code int64       `json:"code"`
	Msg  string      `json:"msg"`
	Data interface{} `json:"data"`
}

type ReqData struct {
	Version string `json:"version"`
	Name    string `json:"name"`
	Body    string `json:"body"`
	Token   string `json:"token"`
	Once    string `json:"once"`
}

type PerformReq struct {
	UserModel   model.User
	UniqueIndex int64
	Once        string
	Name        string
	Msg         []byte
	Token       string
}

type ConnectInfo struct {
	Bot uint `json:"bot"`
}

const CodeSuccess = 200
const CodeFailed = -1

func Perform(conn *websocket.Conn, message []byte, ctx map[string]interface{}) error {
	var err error

	reqData := ReqData{}
	err = json.Unmarshal(message, &reqData)
	if err != nil {
		logrus.Error(err)
		return err
	}

	userModel := ctx["userModel"].(model.User)
	performReq := PerformReq{
		Once:        reqData.Once,
		UserModel:   userModel,
		Name:        reqData.Name,
		Msg:         []byte(reqData.Body),
		Token:       reqData.Token,
		UniqueIndex: ctx["unique_index"].(int64),
	}

	performReqData, err := json.Marshal(performReq)
	if err != nil {
		logrus.Error(err)
		return err
	}

	reqUrl := viper.GetString("bs.url") + "/api/bs/perform"
	respData, err := webutils.PostResp[interface{}](reqUrl, string(performReqData), time.Second*3)
	if err != nil {
		logrus.Error(err)
		return err
	}

	if respData.Code != webutils.CodeSuccess {
		logrus.Error(respData)
		return errors.New(respData.Msg)
	}

	return nil
}

func GamePingMessage(conn *websocket.Conn, message []byte, ctx map[string]interface{}) error {
	if ctx == nil {
		logrus.Error("ctx is nil")
		return nil
	}

	userModel := ctx["userModel"].(model.User)

	event.MustFire(model.EventPing, event.M{
		"user_model": &userModel,
		"conn":       conn,
	})

	performReq := PerformReq{
		UserModel:   userModel,
		Name:        "ping",
		Msg:         message,
		UniqueIndex: ctx["unique_index"].(int64),
	}

	performReqData, err := json.Marshal(performReq)
	if err != nil {
		logrus.Error(err)
		return err
	}

	reqUrl := viper.GetString("bs.url") + "/api/bs/perform"
	respData, err := webutils.PostResp[interface{}](reqUrl, string(performReqData), time.Second*3)
	if err != nil {
		logrus.Error(err)
		return err
	}

	if respData.Code != webutils.CodeSuccess {
		logrus.Error(respData)
		return errors.New(respData.Msg)
	}

	return nil
}

func GameConnect(conn *websocket.Conn, message []byte, ctx map[string]interface{}) error {
	logrus.Debugf("start GameConnect")

	connectInfo := ConnectInfo{}
	err := jsoniter.Unmarshal(message, &connectInfo)
	if err != nil {
		logrus.Errorf("Unmarshal err:%v", err)
		return err
	}

	userModel := ctx["userModel"].(model.User)

	event.MustFire(model.EventConnect, event.M{
		"user_model": &userModel,
		"conn":       conn,
		"is_bot":     connectInfo.Bot,
	})

	logrus.Debug("MustFire EventConnect Finish")

	performReq := PerformReq{
		UserModel:   userModel,
		Name:        "connect",
		Msg:         message,
		UniqueIndex: ctx["unique_index"].(int64),
	}

	performReqData, err := json.Marshal(performReq)
	if err != nil {
		logrus.Error(err)
		return err
	}

	reqUrl := viper.GetString("bs.url") + "/api/bs/perform"
	respData, err := webutils.PostResp[interface{}](reqUrl, string(performReqData), time.Second*3)
	if err != nil {
		logrus.Error(err)
		return err
	}

	logrus.Debugf("req %s Finish, resp:%v", reqUrl, respData)

	if respData.Code != webutils.CodeSuccess {
		logrus.Error(respData)
		return errors.New(respData.Msg)
	}

	return nil
}

func GameDisconnect(conn *websocket.Conn, message []byte, ctx map[string]interface{}) error {
	if ctx == nil {
		return nil
	}

	userModel := ctx["userModel"].(model.User)

	event.MustFire(model.EventDisconnect, event.M{
		"user_model": &userModel,
		"conn":       conn,
	})

	performReq := PerformReq{
		UserModel:   userModel,
		Name:        "disconnect",
		Msg:         message,
		UniqueIndex: ctx["unique_index"].(int64),
	}

	performReqData, err := json.Marshal(performReq)
	if err != nil {
		logrus.Error(err)
		return err
	}

	reqUrl := viper.GetString("bs.url") + "/api/bs/perform"
	respData, err := webutils.PostResp[interface{}](reqUrl, string(performReqData), time.Second*3)
	if err != nil {
		logrus.Error(err)
		return err
	}

	if respData.Code != webutils.CodeSuccess {
		logrus.Error(respData)
		return errors.New(respData.Msg)
	}

	return nil
}
