package web

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"strconv"

	manager "github.com/FloatTech/bot-manager"
	// 依赖gin监听server
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"

	// 前端静态文件
	log "github.com/sirupsen/logrus"
	zero "github.com/wdvxdr1123/ZeroBot"
	"github.com/wdvxdr1123/ZeroBot/message"

	ctrl "github.com/FloatTech/ZeroBot-Plugin/control"
)

var (
	// 向前端推送消息的ws链接
	conn *websocket.Conn
	// 向前端推送日志的ws链接
	logConn *websocket.Conn

	l logWriter
)

// logWriter
// @Description:
//
type logWriter struct {
}

// initGui 初始化gui
func initGui() {
	// 将日志重定向到前端hook
	writer := io.MultiWriter(l, os.Stderr)
	log.SetOutput(writer)
	// 监听后端
	go controller()
	// 注册消息handle
	messageHandle()
}

// websocket的协议升级
var upGrader = websocket.Upgrader{
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

func controller() {
	defer func() {
		err := recover()
		if err != nil {
			log.Errorln("[gui]" + "bot-manager出现不可恢复的错误")
			log.Errorln("[gui]", err)
		}
	}()

	engine := gin.New()
	// 支持跨域
	engine.Use(cors())
	// 注册静态文件
	engine.StaticFS("/dist", http.FS(manager.Dist))
	engine.POST("/get_bots", getBots)
	engine.POST("/get_group_list", getGroupList)
	engine.POST("/get_friend_list", getFriendList)
	// 注册主路径路由，使其跳转到主页面
	engine.GET("/", func(context *gin.Context) {
		context.Redirect(http.StatusMovedPermanently, "/dist/dist/default.html")
	})
	// 更改某个插件状态
	engine.POST("/update_plugin_status", updatePluginStatus)
	// 更改某一个插件在所有群的状态
	engine.POST("/update_plugin_all_group_status", updatePluginAllGroupStatus)
	// 更改所有插件状态
	engine.POST("/update_all_plugin_status", updateAllPluginStatus)
	// 获取所有插件状态
	engine.POST("/get_plugins_status", getPluginsStatus)
	// 获取一个插件状态
	engine.POST("/get_plugin_status", getPluginStatus)
	// 获取插件列表
	engine.POST("/get_plugins", func(context *gin.Context) {
		var datas []map[string]interface{}
		ctrl.ForEach(func(key string, manager *ctrl.Control) bool {
			datas = append(datas, map[string]interface{}{"id": 1, "handle_type": "", "name": key, "enable": manager.IsEnabledIn(0)})
			return true
		})
		context.JSON(200, datas)
	})
	// 链接日志
	engine.GET("/get_log", getLogs)
	// 获取前端标签
	engine.GET("/get_label", func(context *gin.Context) {
		context.JSON(200, "ZeroBot-Plugin")
	})

	// 发送信息
	engine.POST("/send_msg", sendMsg)
	engine.GET("/data", upgrade)
	log.Infoln("[gui] the webui is running http://127.0.0.1:3000")
	log.Infoln("[gui] ", "you input the `ZeroBot-Plugin.exe -g` can disable the gui")
	if err := engine.Run("127.0.0.1:3000"); err != nil {
		log.Debugln("[gui] ", err.Error())
	}
}

// updateAllPluginStatus
/**
 * @Description: 改变所有插件的状态
 * @param context
 * example
 */
func updateAllPluginStatus(context *gin.Context) {
	enable, err := strconv.ParseBool(context.PostForm("enable"))
	if err != nil {
		var parse map[string]interface{}
		err := context.BindJSON(&parse)
		if err != nil {
			log.Errorln("[gui] " + err.Error())
			return
		}
		enable = parse["enable"].(bool)
	}
	ctrl.ForEach(func(key string, manager *ctrl.Control) bool {
		if enable {
			manager.Enable(0)
		} else {
			manager.Disable(0)
		}
		return true
	})
	context.JSON(200, nil)
}

// updatePluginAllGroupStatus
/**
 * @Description: 改变插件在所有群的状态
 * @param context
 * example
 */
func updatePluginAllGroupStatus(context *gin.Context) {
	name := context.PostForm("name")
	enable, err := strconv.ParseBool(context.PostForm("enable"))
	if err != nil {
		var parse map[string]interface{}
		err := context.BindJSON(&parse)
		if err != nil {
			log.Errorln("[gui]" + err.Error())
			return
		}
		name = parse["name"].(string)
		enable = parse["enable"].(bool)
	}
	control, b := ctrl.Lookup(name)
	if !b {
		context.JSON(404, nil)
		return
	}
	if enable {
		control.Enable(0)
	} else {
		control.Disable(0)
	}
	context.JSON(200, nil)
}

// updatePluginStatus
/**
 * @Description: 更改某一个插件状态
 * @param context
 * example
 */
func updatePluginStatus(context *gin.Context) {
	var parse map[string]interface{}
	err := context.BindJSON(&parse)
	if err != nil {
		log.Errorln("[gui] ", err)
		return
	}
	groupID := int64(parse["group_id"].(float64))
	name := parse["name"].(string)
	enable := parse["enable"].(bool)
	fmt.Println(name)
	control, b := ctrl.Lookup(name)
	if !b {
		context.JSON(404, "服务不存在")
		return
	}
	if enable {
		control.Enable(groupID)
	} else {
		control.Disable(groupID)
	}
	context.JSON(200, nil)
}

// getPluginStatus
/**
 * @Description: 获取一个插件的状态
 * @param context
 * example
 */
func getPluginStatus(context *gin.Context) {
	groupID, err := strconv.ParseInt(context.PostForm("group_id"), 10, 64)
	name := context.PostForm("name")
	if err != nil {
		var parse map[string]interface{}
		err := context.BindJSON(&parse)
		if err != nil {
			log.Errorln("[gui]" + err.Error())
			return
		}
		groupID = int64(parse["group_id"].(float64))
		name = parse["name"].(string)
	}
	control, b := ctrl.Lookup(name)
	if !b {
		context.JSON(404, "服务不存在")
		return
	}
	context.JSON(200, gin.H{"enable": control.IsEnabledIn(groupID)})
}

// getPluginsStatus
/**
 * @Description: 获取所有插件的状态
 * @param context
 * example
 */
func getPluginsStatus(context *gin.Context) {
	groupID, err := strconv.ParseInt(context.PostForm("group_id"), 10, 64)
	if err != nil {
		var parse map[string]interface{}
		err := context.BindJSON(&parse)
		if err != nil {
			log.Errorln("[gui]" + err.Error())
			return
		}
		groupID = int64(parse["group_id"].(float64))
	}
	var datas []map[string]interface{}
	ctrl.ForEach(func(key string, manager *ctrl.Control) bool {
		enable := manager.IsEnabledIn(groupID)
		datas = append(datas, map[string]interface{}{"name": key, "enable": enable})
		return true
	})
	context.JSON(200, datas)
}

// getLogs
/**
 * @Description: 连接日志
 * @param context
 * example
 */
func getLogs(context *gin.Context) {
	con1, err := upGrader.Upgrade(context.Writer, context.Request, nil)
	if err != nil {
		return
	}
	logConn = con1
}

// getFriendList
/**
 * @Description: 获取好友列表
 * @param context
 * example
 */
func getFriendList(context *gin.Context) {
	selfID, err := strconv.Atoi(context.PostForm("self_id"))
	if err != nil {
		log.Errorln("[gui]" + err.Error())
		var data map[string]interface{}
		err := context.BindJSON(&data)
		if err != nil {
			log.Errorln("[gui]" + err.Error())
			log.Errorln("[gui]" + "绑定错误")
			return
		}
		selfID = int(data["self_id"].(float64))
	}
	bot := zero.GetBot(int64(selfID))
	var resp []interface{}
	list := bot.GetFriendList().String()
	err = json.Unmarshal([]byte(list), &resp)
	if err != nil {
		log.Errorln("[gui]" + err.Error())
		log.Errorln("[gui]" + "解析json错误")
	}
	context.JSON(200, resp)
}

// getGroupList
/**
 * @Description: 获取群列表
 * @param context
 * example
 */
func getGroupList(context *gin.Context) {
	selfID, err := strconv.Atoi(context.PostForm("self_id"))
	if err != nil {
		var data map[string]interface{}
		err := context.BindJSON(&data)
		if err != nil {
			log.Errorln("[gui]" + err.Error())
			return
		}
		selfID = int(data["self_id"].(float64))
	}

	bot := zero.GetBot(int64(selfID))
	var resp []interface{}
	list := bot.GetGroupList().String()
	err = json.Unmarshal([]byte(list), &resp)
	if err != nil {
		log.Errorln("[gui]" + err.Error())
	}
	context.JSON(200, resp)
}

// getBots
/**
 * @Description: 获取机器人qq号
 * @param context
 * example
 */
func getBots(context *gin.Context) {
	var bots []int64

	zero.RangeBot(func(id int64, ctx *zero.Ctx) bool {
		bots = append(bots, id)
		return true
	})
	context.JSON(200, bots)
}

// MessageHandle
/**
 * @Description: 定义一个向前端发送信息的handle
 * example
 */
func messageHandle() {
	defer func() {
		err := recover()
		if err != nil {
			log.Errorln("[gui]" + "bot-manager出现不可恢复的错误")
			log.Errorln("[gui] ", err)
		}
	}()

	matcher := zero.OnMessage().SetBlock(false).SetPriority(1)

	matcher.Handle(func(ctx *zero.Ctx) {
		if conn != nil {
			err := conn.WriteJSON(ctx.Event)
			if err != nil {
				log.Debugln("[gui] " + "向发送错误")
				return
			}
		}
	})
}

// upgrade
/**
 * @Description: 连接ws，向前端推送message
 * @param context
 * example
 */
func upgrade(context *gin.Context) {
	con, err := upGrader.Upgrade(context.Writer, context.Request, nil)
	if err != nil {
		return
	}
	conn = con
}

// sendMsg
/**
 * @Description: 前端调用发送信息
 * @param context
 * example
 */
func sendMsg(context *gin.Context) {
	var data map[string]interface{}
	err := context.BindJSON(&data)
	if err != nil {
		context.JSON(404, nil)
		return
	}
	selfID := int64(data["self_id"].(float64))
	id := int64(data["id"].(float64))
	message1 := data["message"].(string)
	messageType := data["message_type"].(string)

	bot := zero.GetBot(selfID)
	var msgID int64
	if messageType == "group" {
		msgID = bot.SendGroupMessage(id, message.ParseMessageFromString(message1))
	} else {
		msgID = bot.SendPrivateMessage(id, message.ParseMessageFromString(message1))
	}
	context.JSON(200, msgID)
}

// cors
/**
 * @Description: 支持跨域访问
 * @return gin.HandlerFunc
 * example
 */
func cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method
		origin := c.Request.Header.Get("Origin") // 请求头部
		if origin != "" {
			// 接收客户端发送的origin （重要！）
			c.Writer.Header().Set("Access-Control-Allow-Origin", origin)
			// 服务器支持的所有跨域请求的方法
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE")
			// 允许跨域设置可以返回其他子段，可以自定义字段
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session, Content-Type")
			// 允许浏览器（客户端）可以解析的头部 （重要）
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers")
			// 设置缓存时间
			c.Header("Access-Control-Max-Age", "172800")
			// 允许客户端传递校验信息比如 cookie (重要)
			c.Header("Access-Control-Allow-Credentials", "true")
		}

		// 允许类型校验
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "ok!")
		}

		defer func() {
			if err := recover(); err != nil {
				log.Printf("Panic info is: %v", err)
			}
		}()

		c.Next()
	}
}

func (l logWriter) Write(p []byte) (n int, err error) {
	if logConn != nil {
		err := logConn.WriteMessage(websocket.TextMessage, p)
		if err != nil {
			return len(p), nil
		}
	}
	return len(p), nil
}
