package router

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"reflect"
	"runtime"

	"github.com/gin-gonic/gin"

	"github.com/pingcap/tispector/code"
	"github.com/pingcap/tispector/config"
	"github.com/pingcap/tispector/controller"
	"github.com/pingcap/tispector/util/logger"
)

const (
	test    = 0
	product = 1
)

func Router() *gin.Engine {
	logfile, err := os.Create("./gin_http.log")
	if err != nil {
		fmt.Println("Could not create log file")
	}
	gin.SetMode(gin.DebugMode)
	gin.DefaultWriter = io.MultiWriter(logfile)

	r := gin.Default()

	r.Use(Cors())

	r.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})

	r.POST("/tispector/checksql", HandlerWrapper(controller.CheckSQL))
	r.GET("/tispector/resetRules", HandlerWrapper(controller.InitRuleTable))
	r.POST("/tispector/checksqlbyrules", HandlerWrapper(controller.CheckSQLPRO))
	r.POST("/tispector/checkSQLInFile", HandlerWrapper(controller.CheckSQLInFile))

	file := r.Group("/tispector/file")
	{
		file.POST("/upload", HandlerWrapper(controller.Uploadfile))
		file.GET("/list", HandlerWrapper(controller.LisFiles))
		file.GET("/getfileinfobyname", HandlerWrapper(controller.GetFileByName))
		file.GET("/del", HandlerWrapper(controller.DelFileByName))
		file.POST("/checksqlfile", HandlerWrapper(controller.CheckSQLFile))

	}

	rule := r.Group("/tispector/rule")
	{
		rule.GET("/list", HandlerWrapper(controller.LisRule))
		rule.POST("/update", HandlerWrapper(controller.UpdateRule))
		rule.GET("/getrulebyitem", HandlerWrapper(controller.GetRuleByItem))
		// rule.GET("/initruletable", HandlerWrapper(controller.InitRuleTable))
	}

	cluster := r.Group("/tispector/cluster")
	{
		cluster.GET("/list", HandlerWrapper(controller.ListCluster))
		cluster.POST("/update", HandlerWrapper(controller.UpdateCluster))
		cluster.POST("/del", HandlerWrapper(controller.DelCluster))
		cluster.POST("/add", HandlerWrapper(controller.AddCluster))
		cluster.GET("/getclusterbyname", HandlerWrapper(controller.GetClusterByName))
	}

	return r
}

func Run() {
	if config.Conf.Server.Env == product {
		gin.SetMode(gin.ReleaseMode)
	}

	r := Router()
	r.Use(gin.Recovery())

	err := http.ListenAndServe(fmt.Sprintf(":%s", config.Conf.Server.Port), r)
	if err != nil {
		logger.Errorf(err.Error())
	}
}

type LogicHandler func(c *gin.Context) controller.Resp

func HandlerWrapper(handler LogicHandler) gin.HandlerFunc {
	return func(c *gin.Context) {
		writeResp(getHandleInfo(handler, c), c)
	}
}

func getHandleInfo(handler LogicHandler, c *gin.Context) controller.Resp {
	resp := handler(c)
	if resp.Message == "" && resp.Code == code.Success {
		resp.Message = "success"
	}

	if resp.Code != code.Success {
		logger.Errorf(resp.Message)
	}

	fName := runtime.FuncForPC(reflect.ValueOf(handler).Pointer()).Name()
	user, err := c.Cookie("user")
	if err != nil {
		logger.Warnf("%s get user in wrapper failed", fName)
	}

	if resp.Code == code.Success {
		logger.Infof("%s exec %s success", user, fName)
	} else {
		logger.Infof("%s exec %s failed", user, fName)
	}

	return resp
}

func writeResp(resp controller.Resp, c *gin.Context) {
	c.JSON(200, resp)
}

// Cors 跨域中间件
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, X-Token, Token")
			// 允许浏览器（客户端）可以解析的头部 （重要）
			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 Router() *gin.Engine {
// 	r := gin.Default()

// 	r.GET("/ping", func(c *gin.Context) {
// 		c.JSON(200, gin.H{
// 			"message": "pong",
// 		})
// 	})

// 	r.POST("/db-injection/login", HandlerWrapper(controller.Login))

// 	r.Use(controller.AuthorizeJWT())

// 	task := r.Group("/db-injection/task")
// 	{
// 		task.POST("/add", HandlerWrapper(controller.AddTask))
// 		task.POST("/reviewer/list", HandlerWrapper(controller.ListReviewerTask))
// 		task.POST("/exec/list", HandlerWrapper(controller.ListExecTask))
// 		task.POST("/history", HandlerWrapper(controller.ListHistoryTask))
// 		task.POST("/get", HandlerWrapper(controller.GetTask))
// 		task.POST("/update", HandlerWrapper(controller.UpdateTask))
// 	}

// 	r.POST("/db-injection/rule/list", HandlerWrapper(controller.LisRule))
// 	r.POST("/db-injection/db/list", HandlerWrapper(controller.ListDB))

// 	backup := r.Group("/db-injection/backup")
// 	{
// 		backup.POST("/data", HandlerWrapper(controller.ListRollbackData))
// 		backup.POST("/rollback", HandlerWrapper(controller.Rollback))
// 	}

// 	r.Use(controller.OnlyDba())

// 	r.POST("/db-injection/rule/update", HandlerWrapper(controller.UpdateRuleStatus))

// 	cluster := r.Group("/db-injection/cluster")
// 	{
// 		cluster.POST("/list", HandlerWrapper(controller.ListCluster))
// 		cluster.POST("/update", HandlerWrapper(controller.UpdateCluster))
// 		cluster.POST("/del", HandlerWrapper(controller.DelCluster))
// 		cluster.POST("/add", HandlerWrapper(controller.AddCluster))
// 	}

// 	return r
// }
