package web
import (
"embed"
"fmt"
"html/template"
"net/http"
"naviwatcher/internal/config"
"naviwatcher/internal/database"
)
//go:embed templates/*.html
var templates embed.FS
// dashboardTmpl is parsed once at package init from the embedded templates.
var dashboardTmpl = template.Must(template.ParseFS(templates, "templates/dashboard.html"))
// handleDashboard renders the artist dashboard: monitored artists with their
// missing-release counts.
func (s *Server) handleDashboard(w http.ResponseWriter, r *http.Request) {
// Only serve the index at "/" (and not e.g. "/favicon.ico" fallthroughs).
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
threshold := s.defaultThreshold()
data, err := s.buildDashboardData(r.Context(), threshold)
if err != nil {
http.Error(w, fmt.Sprintf("failed to build dashboard: %v", err), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
if err := dashboardTmpl.Execute(w, data); err != nil {
http.Error(w, fmt.Sprintf("template render error: %v", err), http.StatusInternalServerError)
}
}
// defaultThreshold returns the fuzzy threshold to use when scanning for the
// dashboard. It is currently fixed at the engine default; later wiring can
// thread the configured threshold through the Server if desired.
func (s *Server) defaultThreshold() float64 {
return 0 // 0 → scanner.DefaultThreshold
}
// NewServerWithConfig is a convenience constructor that accepts the full
// *config.Config (mirroring how the app constructs other components). It
// forwards the server sub-config and derives uiBaseURL from host/port.
func NewServerWithConfig(cfg *config.Config, db *database.DB) *Server {
// Build a best-effort external base URL from the server config.
base := fmt.Sprintf("http://%s:%d", cfg.Server.Host, cfg.Server.Port)
return NewServer(&cfg.Server, db, base)
}