// Package router ...
//
// Description : router ...
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2025-02-07 18:19
package router

import (
	"fmt"
	"net/http"
	"os"
	"reflect"
	"runtime"
	"strings"
	"sync"

	apiDocDefine "git.zhangdeman.cn/zhangdeman/api-doc/define"
	"git.zhangdeman.cn/zhangdeman/api-doc/enums"
	"git.zhangdeman.cn/zhangdeman/api-doc/openapi"
	"git.zhangdeman.cn/zhangdeman/consts"
	"git.zhangdeman.cn/zhangdeman/gin/define"
	"git.zhangdeman.cn/zhangdeman/graceful"
	"github.com/jedib0t/go-pretty/v6/table"
	"github.com/jedib0t/go-pretty/v6/text"

	"git.zhangdeman.cn/zhangdeman/gin/middleware"
	"git.zhangdeman.cn/zhangdeman/gin/middleware/request_cors"
	"github.com/gin-contrib/pprof"

	"github.com/gin-gonic/gin"
)

// NewServerOption ...
func NewServerOption(port int, optionList ...SetServerOptionFunc) *serverOption {
	return newServerOption(port, optionList...)
}

func newServerOption(port int, optionList ...SetServerOptionFunc) *serverOption {
	option := &serverOption{
		globalMiddlewareList: nil,
	}
	for _, opt := range optionList {
		if nil == opt {
			continue
		}
		opt(option)
	}
	return option
}

// NewServer server实例
func NewServer(port int, optionList ...SetServerOptionFunc) *server {
	if port < 80 {
		panic("port should be greater than 80")
	}
	gin.SetMode(gin.ReleaseMode)
	option := newServerOption(port, optionList...)

	// 启用文档, 初始化文档
	if option.docConfig.Enable {
		if len(option.docConfig.BaseUri) == 0 {
			option.docConfig.BaseUri = "/_doc/swagger" // 未指定文档基础路径, 则以默认值作为基础路径
		}
		if len(option.docConfig.Flag) == 0 {
			option.docConfig.Flag = fmt.Sprintf("%v", port) // 未指定文档实例标识, 则以监听端口作为实例
		}
		// base_uri 拼接 文档标识, 作为最终 baseUri
		option.docConfig.BaseUri = fmt.Sprintf("%v/%v", strings.TrimRight(option.docConfig.BaseUri, "/"), strings.Trim(option.docConfig.Flag, "/"))
		optionFuncList := []openapi.OptionFunc{
			openapi.WithInfo(option.docConfig.Info),
			openapi.WithSecurity(option.docConfig.SecuritySchemes),
			openapi.WithCommonParameter(option.docConfig.CommonParameter),
		}
		if nil != option.docConfig.ServerList {
			optionFuncList = append(optionFuncList, openapi.WithServers(*option.docConfig.ServerList))
		}
		openapi.DocManager.NewOpenApiDoc(option.docConfig.Flag, optionFuncList...)
	}
	s := &server{
		router:                   gin.Default(),
		port:                     port,
		option:                   option,
		lock:                     &sync.RWMutex{},
		commonParam:              map[string]GetCommonParam{},
		consoleOutput:            [][]any{},
		globalMiddlewareList:     []gin.HandlerFunc{},
		globalMiddlewareDescList: []string{},
		uriTable:                 map[string]define.UriConfig{},
	}
	s.getGlobalMiddlewareList(option)
	// 注册全局中间件
	s.router.Use(s.globalMiddlewareList...)
	// 启用pprof, 注册相关路由
	if option.enablePprof {
		pprof.Register(s.router)
	}
	return s
}

type server struct {
	router                   *gin.Engine
	port                     int
	option                   *serverOption
	commonParam              map[string]GetCommonParam // 结构体字段名, 注意, 不是TAG
	lock                     *sync.RWMutex
	consoleOutput            [][]any                     // 控制台输出的提示信息
	globalMiddlewareList     []gin.HandlerFunc           // 全局中间件列表
	globalMiddlewareDescList []string                    // 全局中间件描述列表
	uriTable                 map[string]define.UriConfig // uri配置表
}

func (s *server) getGlobalMiddlewareList(option *serverOption) {
	// 全局 panic 捕获
	s.globalMiddlewareList = append(s.globalMiddlewareList, middleware.CustomRecover())
	// 全局流控中间件
	s.globalMiddlewareList = append(s.globalMiddlewareList, middleware.RateLimit(s.option.rateLimitInstance, s.uriTable))
	if nil != option.initContextData {
		s.globalMiddlewareList = append(s.globalMiddlewareList, option.initContextData) // 初始化一些全局的变量
	}
	if !option.disableInitRequest { // 启用了初始化请求
		s.globalMiddlewareList = append(s.globalMiddlewareList, middleware.InitRequest) // 初始化请求
	}
	if nil != option.loggerCfg {
		// 请求日志记录中间件
		s.globalMiddlewareList = append(s.globalMiddlewareList, middleware.LogRequest(option.loggerCfg))
	}
	if option.enableCors {
		// 跨域中间件
		s.globalMiddlewareList = append(s.globalMiddlewareList, request_cors.New(request_cors.Config{
			AllowAllOrigins:        true,
			AllowOrigins:           nil,
			AllowOriginFunc:        nil,
			AllowMethods:           []string{"*"},
			AllowHeaders:           []string{"*"},
			AllowCredentials:       true,
			ExposeHeaders:          nil,
			MaxAge:                 0,
			AllowWildcard:          true,
			AllowBrowserExtensions: true,
			AllowWebSockets:        true,
			AllowFiles:             true,
		}))
	}
	if len(option.globalMiddlewareList) > 0 {
		// 自定义全局中间件追加
		s.globalMiddlewareList = append(s.globalMiddlewareList, option.globalMiddlewareList...)
	}
	s.globalMiddlewareDescList = s.getMiddlewareDescList(s.globalMiddlewareList)
}

// RegisterDocHandler 注册文档路由
func (s *server) RegisterDocHandler() {
	if !s.option.docConfig.Enable {
		return
	}

	s.router.GET(s.option.docConfig.BaseUri+"/*any", func(ctx *gin.Context) {
		if ctx.Request.RequestURI == s.option.docConfig.BaseUri+"/doc.json" || ctx.Request.RequestURI == s.option.docConfig.BaseUri+"/knife4go/doc.json" {
			// 默认swagger, 通过此接口读取文档数据
			ctx.JSON(http.StatusOK, openapi.DocManager.DocData(s.option.docConfig.Flag))
			ctx.Abort()
		}
		if ctx.Request.RequestURI == "/doc/swagger/openapi.json" {
			// knife4go 文档通过此接口读取文档列表
			ctx.JSON(http.StatusOK, []map[string]any{
				{
					"name":           "服务文档",
					"url":            "doc.json",
					"swaggerVersion": enums.SwaggerDocVersion3.String(),
				},
			})
			ctx.Abort()
		}
	}, NewSwaggerUI(fmt.Sprintf("[%v]接口文档", s.option.docConfig.Flag), s.option.docConfig.BaseUri, consts.SwaggerUITheme(s.option.docConfig.UiTheme)).Handler())
	s.router.GET("/swagger-resources", func(ctx *gin.Context) { // lucky UI获取分组信息
		ctx.Writer.Header().Set("Access-Control-Allow-Origin", "*") // 允许访问所有域
		ctx.JSON(http.StatusOK, []map[string]any{
			{
				"name":           "服务文档",
				"url":            s.option.docConfig.BaseUri + "/doc.json",
				"swaggerVersion": enums.SwaggerDocVersion3.String(),
			},
		})
		// ctx.JSON(http.StatusOK, swaggerInstance.docInstance.Data())
	})
}

// Start 启动服务
func (s *server) Start() {
	// 注册文档
	s.RegisterDocHandler()
	// s.uiInstance.RegisterHandler(s.router, s.option.swaggerBaseUri)
	gracefulServer := graceful.NewServer(fmt.Sprintf(":%d", s.port), s.Router())
	defer func() {
		_ = gracefulServer.Close()
	}()
	s.TableOutput(nil, nil) // 控制台打印路由表格
	if err := gracefulServer.ListenAndServe(); err != nil {
		if strings.Contains(err.Error(), "use of closed network connection") {
			fmt.Println("接收到退出指令, 服务平滑关闭")
			return
		}
		panic("服务启动监听失败" + err.Error())
	}
}

// Router 对外访问路由实例, 不建议直接用
func (s *server) Router() *gin.Engine {
	return s.router
}

// Handler404 注册404的处理方法
func (s *server) Handler404(f gin.HandlerFunc) {
	s.router.NoRoute(f)
}

// SetCustomRouter 自定义路由处理
func (s *server) SetCustomRouter(f func(r *gin.Engine)) {
	if nil == f {
		return
	}
	f(s.router)
}

// Group 注册接口路由
func (s *server) Group(routerPrefix string, middlewareList []gin.HandlerFunc, controllerList ...any) {
	routerGroup := s.router.Group(routerPrefix)
	routerGroup.Use(middlewareList...)
	parser := controllerParser{}
	middlewareDescList := append([]string{}, s.globalMiddlewareDescList...)
	middlewareDescList = append(middlewareDescList, s.getMiddlewareDescList(middlewareList)...)
	for _, itemController := range controllerList {
		urlTable := parser.Parse(itemController)
		for _, itemUriCfg := range urlTable {
			// 设置代理请求函数描述
			apiMiddlewareList := append([]string{}, middlewareDescList...)
			if itemUriCfg.IsSse {
				apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(reflect.ValueOf(s.SseHandler).Pointer()).Name())
			} else {
				apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(reflect.ValueOf(s.RequestHandler).Pointer()).Name())
			}
			// 设置 超时 函数
			apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(reflect.ValueOf(middleware.Timeout).Pointer()).Name())
			// 设置 logic 函数描述
			apiMiddlewareList = append(apiMiddlewareList, runtime.FuncForPC(itemUriCfg.ApiLogicFunc.Func.Pointer()).Name())

			// _ = s.uiInstance.DocInstance().AddApiFromInAndOut(routerPrefix, itemUriCfg.FormDataType, itemUriCfg.ResultDataType)
			// 普通 HTTP 请求
			handleFunc := s.RequestHandler(itemUriCfg)
			if itemUriCfg.IsSse {
				// SSE 连接
				handleFunc = s.SseHandler(itemUriCfg)
			}
			// 一个接口支持注册多种请求方法
			for _, method := range itemUriCfg.RequestMethod {
				if len(routerPrefix) > 0 {
					routerPrefix = "/" + strings.TrimSuffix(strings.TrimPrefix(routerPrefix, "/"), "/")
				}
				fullUriPath := routerPrefix + "/" + strings.TrimPrefix(itemUriCfg.Path, "/")
				// 注册接口文档
				_ = openapi.DocManager.AddApiDoc(s.option.docConfig.Flag, apiDocDefine.UriConfig{
					Path:          fullUriPath,
					RequestMethod: method,
					TagList:       itemUriCfg.TagList,
					Desc:          itemUriCfg.Desc,
				}, itemUriCfg.FormDataType, itemUriCfg.ResultDataType)
				s.uriTable[fullUriPath] = itemUriCfg // 注册路由时存储 接口路径 => 接口配置的信息
				s.consoleOutput = append(s.consoleOutput, []any{
					fullUriPath,
					strings.ToUpper(method),
					strings.Join(apiMiddlewareList, "\n"),
				})
				s.registerRouter(routerGroup, method, itemUriCfg, handleFunc)
			}
		}
	}
}

// registerRouter 注册路由
func (s *server) registerRouter(routerGroup *gin.RouterGroup, method string, itemUriCfg define.UriConfig, handleFunc gin.HandlerFunc) {
	funcList := []gin.HandlerFunc{
		middleware.Timeout(itemUriCfg.MaxExecTime), // 超时处理
		handleFunc,
	}
	switch method {
	case http.MethodGet:
		routerGroup.GET(itemUriCfg.Path, handleFunc)
	case http.MethodHead:
		routerGroup.HEAD(itemUriCfg.Path, funcList...)
	case http.MethodPost:
		routerGroup.POST(itemUriCfg.Path, funcList...)
	case http.MethodPut:
		routerGroup.PUT(itemUriCfg.Path, funcList...)
	case http.MethodPatch:
		routerGroup.PATCH(itemUriCfg.Path, funcList...)
	case http.MethodDelete:
		routerGroup.DELETE(itemUriCfg.Path, funcList...)
	case http.MethodOptions:
		routerGroup.OPTIONS(itemUriCfg.Path, funcList...)
	case http.MethodTrace:
		panic(`method Trace is not supported`)
	default:
		panic("method " + method + " is not support")
	}
}

// getMiddlewareDescList 获取中间件路径的描述列表
func (s *server) getMiddlewareDescList(middlewareList []gin.HandlerFunc) []string {
	middlewareDescList := []string{}
	for _, itemMiddleware := range middlewareList {
		middlewareValue := reflect.ValueOf(itemMiddleware)
		// 获取函数的指针
		funcPointer := middlewareValue.Pointer()
		// 通过 runtime 获取函数信息
		funcInfo := runtime.FuncForPC(funcPointer)
		// 获取完整的函数名称（包含包路径）
		fullName := funcInfo.Name()
		middlewareDescList = append(middlewareDescList, fullName)
	}
	return middlewareDescList
}

// TableOutput 表格输出
func (s *server) TableOutput(header []any, footer []any) {
	// 帮助函数
	anySlice2TableRow := func(input []any) table.Row {
		tableRowData := make(table.Row, 0, len(input))
		for _, d := range input {
			tableRowData = append(tableRowData, d)
		}
		return tableRowData
	}
	// 实例化一个表格
	t := table.NewWriter()
	t.SetColumnConfigs([]table.ColumnConfig{
		{
			Number:    1,
			AutoMerge: false,
			VAlign:    text.VAlignMiddle,
		},
		{
			Number:    2,
			AutoMerge: false,
			VAlign:    text.VAlignMiddle,
		},
	})
	// 标准输出
	t.SetOutputMirror(os.Stdout)
	if len(header) > 0 {
		t.AppendHeader(anySlice2TableRow(header))
	}
	for _, row := range s.consoleOutput {
		t.AppendRow(anySlice2TableRow(row))
		t.AppendSeparator()
	}
	if len(footer) > 0 {
		t.AppendFooter(anySlice2TableRow(footer))
	}
	t.Render()
}
