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

import (
	"net/http"
	"path/filepath"
	"strings"

	"git.zhangdeman.cn/zhangdeman/api-doc/enums"
	"git.zhangdeman.cn/zhangdeman/consts"
	"git.zhangdeman.cn/zhangdeman/gin/router/theme"
	"github.com/gin-gonic/gin"
	knife4goFiles "github.com/go-webtools/knife4go"
	knife4goGin "github.com/go-webtools/knife4go/gin"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
)

// NewSwaggerUI ...
func NewSwaggerUI(docTitle string, docBaseUri string, uiTheme consts.SwaggerUITheme) *SwaggerUI {
	return &SwaggerUI{
		baseUri:  docBaseUri,
		docTitle: docTitle,
		uiTheme:  uiTheme,
	}
}

type SwaggerUI struct {
	baseUri  string
	docTitle string
	uiTheme  consts.SwaggerUITheme // 文档主题, swaggerUI / knife4go, 默认 knife4go
}

// Handler 访问文档的接口处理
func (su *SwaggerUI) Handler() func(ctx *gin.Context) {
	switch su.uiTheme {
	case consts.SwaggerUIThemeKnife4go:
		return su.HandleKnife4goUI()
	case consts.SwaggerUIThemeYDocLucky:
		// YDoc-Lucky-UI 主题处理
		return su.HandleLuckyUI()
	case consts.SwaggerUIThemeDefault:
		return su.HandleSwaggerUI()
	case consts.SwaggerUIThemeRedocFree:
		// redoc免费版
		return su.HandleRedocFreeUI()
	case consts.SwaggerUIThemeElements:
		return su.HandleElements()
	default:
		return su.HandleSwaggerUI()
	}
}

func (su *SwaggerUI) HandleElements() gin.HandlerFunc {
	return func(ctx *gin.Context) {
		fileRealPath := strings.TrimPrefix(ctx.Request.RequestURI, su.baseUri)
		byteData, _ := theme.ElementsFiles.ReadFile(filepath.Join("elements", fileRealPath))
		if strings.Contains(ctx.Request.RequestURI, ".html") {
			byteData = []byte(strings.ReplaceAll(string(byteData), "{{BASE_URI}}", su.baseUri))
			byteData = []byte(strings.ReplaceAll(string(byteData), "{{DOC_TITLE}}", su.docTitle))
			byteData = []byte(strings.ReplaceAll(string(byteData), "{{DOC_PATH}}", "doc.json"))
			ctx.Header(consts.HeaderKeyContentType.String(), "text/html; charset=utf-8")
			ctx.String(http.StatusOK, string(byteData))
			ctx.Abort()
			return
		}
		uriArr := strings.Split(ctx.Request.RequestURI, ".")
		contentType := "text/" + uriArr[len(uriArr)-1]
		if strings.HasSuffix(ctx.Request.RequestURI, "png") {
			contentType = "image/png"
		} else if strings.HasSuffix(ctx.Request.RequestURI, "js") {
			contentType = "application/javascript"
		}
		ctx.Header(consts.HeaderKeyContentType.String(), contentType)
		ctx.String(http.StatusOK, string(byteData))
		ctx.Abort()
	}
}

// HandleLuckyUI ...
func (su *SwaggerUI) HandleLuckyUI() func(ctx *gin.Context) {
	// su.router.StaticFS(su.baseUri+"/assets", http.FS(ydocUIFiles))
	return func(ctx *gin.Context) {
		fileRealPath := strings.TrimPrefix(ctx.Request.RequestURI, su.baseUri)
		byteData, _ := theme.YdocUIFiles.ReadFile(filepath.Join(enums.SwaggerUIThemeYDocLucky.String(), fileRealPath))
		if strings.HasSuffix(ctx.Request.RequestURI, "html") {
			byteData = []byte(strings.ReplaceAll(string(byteData), "{{BASE_URI}}", su.baseUri))
		}
		uriArr := strings.Split(ctx.Request.RequestURI, ".")
		contentType := "text/" + uriArr[len(uriArr)-1]
		if strings.HasSuffix(ctx.Request.RequestURI, "png") {
			contentType = "image/png"
		} else if strings.HasSuffix(ctx.Request.RequestURI, "js") {
			contentType = "application/javascript"
		}
		ctx.Header(consts.HeaderKeyContentType.String(), contentType)
		ctx.String(http.StatusOK, string(byteData))
		ctx.Abort()
	}
}

// HandleKnife4goUI ...
func (su *SwaggerUI) HandleKnife4goUI() func(ctx *gin.Context) {
	resetOption := func(cfg *knife4goGin.Config) {
		if nil == cfg {
			return
		}
		cfg.Title = "服务接口文档"
	}
	return knife4goGin.WrapHandler(knife4goFiles.Handler, resetOption)
}

// HandleSwaggerUI ...
func (su *SwaggerUI) HandleSwaggerUI() func(ctx *gin.Context) {
	return ginSwagger.WrapHandler(swaggerFiles.Handler)
}

// HandleRedocFreeUI 处理redoc_free主题
func (su *SwaggerUI) HandleRedocFreeUI() func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		// TODO : 这部分数据支持外部传参替换
		replaceTable := map[string]string{
			"{{DOC_TITLE}}":           su.docTitle,
			"{{CSS_FAMILY}}":          "https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700",
			"{{DOC_PATH}}":            "doc.json",
			"{{REDOC_STANDALONE_JS}}": "https://cdn.redoc.ly/redoc/latest/bundles/redoc.standalone.js",
		}
		for k, v := range replaceTable {
			theme.RedocFreeIndexContent = strings.ReplaceAll(theme.RedocFreeIndexContent, k, v)
		}
		ctx.Header(consts.HeaderKeyContentType.String(), "text/html; charset=utf-8")
		ctx.String(http.StatusOK, theme.RedocFreeIndexContent)
		ctx.Abort()
	}
}
