package spahandler

import (
	"fmt"
	"io/fs"
	"net/http"
	"os"
	"path/filepath"
	"text/template"

	"github.com/olivere/vite"
	"github.com/rs/zerolog/log"

	"xtablo-backend/internal/frontend"
)

type handler struct {
	distFS fs.FS
}

func NewHandler() *handler {
	distFS, err := fs.Sub(frontend.DistFS, "dist")
	if err != nil {
		panic(fmt.Errorf("creating sub-filesystem for 'dist' directory: %w", err))
	}
	return &handler{
		distFS: distFS,
	}
}

func (h *handler) GetAssets() http.HandlerFunc {
	return http.FileServerFS(h.distFS).ServeHTTP
}

func (h *handler) GetSpa() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		defer func() {
			if err != nil {
				log.Err(err).Msg(err.Error())
			}
		}()

		if r.URL.Path == "/" || r.URL.Path == "/index.html" {
			viteFragment, err := vite.HTMLFragment(vite.Config{
				FS:    h.distFS,
				IsDev: false,
			})
			if err != nil {
				log.Err(err).Msg(err.Error())
				http.Error(w, "Error instantiating vite fragment", http.StatusInternalServerError)
				return
			}

			tmpl, err := template.New("index").Parse(indexTmpl)
			if err != nil {
				http.Error(w, "Error parsing template", http.StatusInternalServerError)
				return
			}

			if err = tmpl.Execute(w, map[string]interface{}{
				"Vite": viteFragment,
			}); err != nil {
				http.Error(w, "Error executing template", http.StatusInternalServerError)
				return
			}
			return
		}

		// Serve the public files generated by Vite. By default, these files are
		// referenced in the DOM with a root-relative URL format (e.g. '/file.ext').
		http.ServeFileFS(w, r, h.distFS, filepath.Base(r.URL.Path))
	}
}

func (h *handler) GetDevSpa() http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var err error
		defer func() {
			if err != nil {
				log.Err(err).Msg(err.Error())
			}
		}()
		if r.URL.Path == "/" || r.URL.Path == "/index.html" {
			viteFragment, err := vite.HTMLFragment(vite.Config{
				FS:           os.DirFS("ui"),
				IsDev:        true,
				ViteURL:      "http://localhost:5173",
				ViteTemplate: vite.SvelteTs,
				ViteEntry:    "/src/main.ts",
			})

			if err != nil {
				http.Error(w, "Error instantiating vite fragment", http.StatusInternalServerError)
				return
			}

			tmpl, err := template.New("index").Parse(indexTmpl)
			if err != nil {
				http.Error(w, "Error parsing template", http.StatusInternalServerError)
				return
			}

			if err = tmpl.Execute(w, map[string]interface{}{
				"Vite": viteFragment,
			}); err != nil {
				http.Error(w, "Error executing template", http.StatusInternalServerError)
				return
			}
			return
		}

		// Serve files in the public directory. By default, these files are
		// referenced in the DOM with a root-relative URL format (e.g. '/file.ext').
		http.ServeFileFS(w, r, os.DirFS("./public"), filepath.Base(r.URL.Path))
	}
}

var indexTmpl = `<!doctype html>
<html lang="en" class="h-full scroll-smooth">
  <head>
    <meta charset="UTF-8" />
		{{ .Vite.Tags }}
 </head>
  <body class="w-100">
    <div id="app"></div>
  </body>
</html>
`
