package dashboard

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

	"github.com/gobuffalo/packr/v2"
	"k8s.io/klog/v2"
)

var assetBox = (*packr.Box)(nil)

// getAssetBox returns a binary-friendly set of assets packaged from disk
func getAssetBox() *packr.Box {
	if assetBox == (*packr.Box)(nil) {
		assetBox = packr.New("Assets", "assets")
	}
	return assetBox
}

// Asset replies with the contents of the loaded asset from disk
func Asset(assetPath string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		asset, err := getAssetBox().Find(assetPath)
		if err != nil {
			klog.Errorf("Error getting asset: %v", err)
			http.Error(w, "Error getting asset", http.StatusInternalServerError)
			return
		}
		_, err = w.Write(asset)
		if err != nil {
			klog.Errorf("Error writing asset: %v", err)
		}
	})
}

// StaticAssets replies with a FileServer for all assets, the prefix is used to strip the URL path
func StaticAssets(prefix string) http.Handler {
	klog.V(3).Infof("stripping prefix: %s", prefix)
	return http.StripPrefix(prefix, http.FileServer(getAssetBox()))
}

// mimeTypes maps file extensions to MIME types
var mimeTypes = map[string]string{
	".css":   "text/css",
	".js":    "application/javascript",
	".svg":   "image/svg+xml",
	".ico":   "image/x-icon",
	".png":   "image/png",
	".jpg":   "image/jpeg",
	".jpeg":  "image/jpeg",
	".gif":   "image/gif",
	".woff":  "font/woff",
	".woff2": "font/woff2",
	".ttf":   "font/ttf",
	".eot":   "application/vnd.ms-fontobject",
}

// ServeStaticFile serves a static file with the correct MIME type
func ServeStaticFile(w http.ResponseWriter, r *http.Request, path string) {
	ext := filepath.Ext(path)
	if mimeType, ok := mimeTypes[ext]; ok {
		w.Header().Set("Content-Type", mimeType)
	}
	http.ServeFile(w, r, path)
}

// StaticHandler returns an http.HandlerFunc that serves static files
func StaticHandler(prefix, root string) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// Strip prefix from path
		path := r.URL.Path[len(prefix):]
		fullPath := filepath.Join(root, path)

		// Basic security check - ensure path doesn't go above root
		if !strings.HasPrefix(filepath.Clean(fullPath), root) {
			http.Error(w, "Invalid path", http.StatusBadRequest)
			return
		}

		ServeStaticFile(w, r, fullPath)
	}
}
