package resources

import (
	"embed"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"io/fs"
	"net/http"
	"os"
	"path"
	"path/filepath"
	"strings"
)

//go:embed assets/index.html
var index []byte

//go:embed assets/assets
var Static embed.FS

//go:embed images
var Images embed.FS

//go:embed assets/favicon.ico
var ICO embed.FS

//go:embed template/defaultAvatar.jpg
var DefaultAvatar embed.FS

//go:embed app/index.html
var app []byte

//go:embed app
var APP embed.FS

const (
	apiBase     = "/api/v1"
	adminApi    = "/admin-api/"
	assetsProxy = "assets"
)

func HtmlRouteHandler() gin.HandlerFunc {
	return func(context *gin.Context) {
		var uri = context.Request.URL.Path
		var ext = path.Ext(uri)
		if find := strings.Contains(uri, apiBase); find {
			return
		} else if find = ext == ".txt"; find {
			//打开文件
			file, err := os.Open("." + uri)
			defer file.Close()
			if err != nil {
				fmt.Println("打开文件错误", err)
			}
			context.File("." + uri)
			context.Abort()
			return
		}
		accept := context.Request.Header.Get("Accept")
		if strings.Contains(accept, "text/html") {
			writeIndex(context)
		}
	}
}

func writeIndex(context *gin.Context) {
	agent := context.Request.Header.Get("User-Agent")
	if strings.Contains(strings.ToLower(agent), "mobile") {
		context.Redirect(http.StatusFound, "/app")
		return
	}
	context.Writer.WriteHeader(200)
	context.Writer.Header().Add("Accept", "text/html")
	_, _ = context.Writer.Write(index)
	context.Writer.Flush()
	context.Abort()
}

type Resource struct {
	fs   embed.FS
	path string
}

func NewResource() *Resource {
	return &Resource{
		fs:   Static,
		path: "assets",
	}
}

func NewAppResource() *Resource {
	return &Resource{
		fs:   APP,
		path: "app/",
	}
}

func NewImagesResource() *Resource {
	return &Resource{
		fs:   Images,
		path: "images/",
	}
}

func (r *Resource) Open(name string) (fs.File, error) {
	if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) {
		return nil, errors.New("http: invalid character in file path")
	}
	fullName := r.getFullName(name)
	file, err := r.fs.Open(fullName)
	return file, err
}

func (r *Resource) getFullName(name string) string {
	if r.path == "assets" {
		return r.path + "/assets/" + name
	}
	return r.path + name
}

func InitResource(engine *gin.Engine) {
	resourceRouter(engine)
	engine.StaticFS("/assets", http.FS(NewResource()))
	engine.StaticFS("/app", http.FS(NewAppResource()))
	engine.StaticFS("/images", http.FS(NewImagesResource()))
}

type HtmlHandler struct{}

func NewHtmlHandler() *HtmlHandler {
	return &HtmlHandler{}
}

// RedirectIndex 404 重定向
func (h *HtmlHandler) RedirectIndex(context *gin.Context) {
	var uri = context.Request.URL.Path
	if strings.Contains(uri, adminApi) {
		context.Abort()
		return
	}
	accept := context.Request.Header.Get("Accept")
	if strings.Contains(accept, "text/html") {
		writeIndex(context)
	}
}

func (h *HtmlHandler) Index(context *gin.Context) {
	writeIndex(context)
}

func (h *HtmlHandler) App(context *gin.Context) {
	context.Writer.WriteHeader(200)
	context.Writer.Header().Add("Accept", "text/html")
	_, _ = context.Writer.Write(app)
	context.Writer.Flush()
	context.Abort()
}

// resourceRouter 静态资源配置
func resourceRouter(engine *gin.Engine) {
	html := NewHtmlHandler()
	group := engine.Group("/")
	{
		group.GET("", html.Index)
		group.GET("/app", html.App)
		group.GET("/defaultAvatar", func(context *gin.Context) {
			context.Request.URL.Path = "template/defaultAvatar.jpg"
			staticServer := http.FileServer(http.FS(DefaultAvatar))
			staticServer.ServeHTTP(context.Writer, context.Request)
			context.Abort()
		})
		group.GET("favicon.ico", func(context *gin.Context) {
			context.Request.URL.Path = assetsProxy + context.Request.URL.Path
			staticServer := http.FileServer(http.FS(ICO))
			staticServer.ServeHTTP(context.Writer, context.Request)
			context.Abort()
		})
	}
	// 解决刷新 404 问题
	engine.NoRoute(html.RedirectIndex)
}