package handlers

import (
	"encoding/json"
	"html/template"
	"io/fs"
	"log"
	"net/http"
	"strconv"
	"sync"

	"setec-manager/internal/config"
	"setec-manager/internal/db"
	"setec-manager/internal/hosting"
	"setec-manager/web"

	"github.com/go-chi/chi/v5"
)

type Handler struct {
	Config         *config.Config
	DB             *db.DB
	HostingConfigs *hosting.ProviderConfigStore
	tmpl           *template.Template
	once           sync.Once
}

func New(cfg *config.Config, database *db.DB, hostingConfigs *hosting.ProviderConfigStore) *Handler {
	return &Handler{
		Config:         cfg,
		DB:             database,
		HostingConfigs: hostingConfigs,
	}
}

func (h *Handler) getTemplates() *template.Template {
	h.once.Do(func() {
		funcMap := template.FuncMap{
			"eq":      func(a, b interface{}) bool { return a == b },
			"ne":      func(a, b interface{}) bool { return a != b },
			"default": func(val, def interface{}) interface{} {
				if val == nil || val == "" || val == 0 || val == false {
					return def
				}
				return val
			},
		}

		var err error
		h.tmpl, err = template.New("").Funcs(funcMap).ParseFS(web.TemplateFS, "templates/*.html")
		if err != nil {
			log.Fatalf("Failed to parse templates: %v", err)
		}

		// Also parse from the static FS to make sure it's available
		_ = fs.WalkDir(web.StaticFS, ".", func(path string, d fs.DirEntry, err error) error {
			return nil
		})
	})
	return h.tmpl
}

type pageData struct {
	Title  string
	Data   interface{}
	Config *config.Config
}

func (h *Handler) render(w http.ResponseWriter, name string, data interface{}) {
	pd := pageData{
		Data:   data,
		Config: h.Config,
	}

	t := h.getTemplates().Lookup(name)
	if t == nil {
		http.Error(w, "Template not found: "+name, http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "text/html; charset=utf-8")
	if err := t.Execute(w, pd); err != nil {
		log.Printf("[template] %s: %v", name, err)
	}
}

func writeJSON(w http.ResponseWriter, status int, v interface{}) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)
	json.NewEncoder(w).Encode(v)
}

func writeError(w http.ResponseWriter, status int, msg string) {
	writeJSON(w, status, map[string]string{"error": msg})
}

func paramInt(r *http.Request, name string) (int64, error) {
	return strconv.ParseInt(chi.URLParam(r, name), 10, 64)
}

func paramStr(r *http.Request, name string) string {
	return chi.URLParam(r, name)
}
