package handlers

import (
	"context"
	"log/slog"
	"net/http"
	"time"

	"lookbook/internal/data/session"
)

// Router wraps http.ServeMux and automatically injects RequestContext into handlers.
type Router struct {
	mux *http.ServeMux
	rc  *RequestContext
}

func NewRouter(rc *RequestContext) *Router {
	return &Router{
		mux: http.NewServeMux(),
		rc:  rc,
	}
}

// Handle registers a handler that returns an error.
// The RequestContext is automatically injected and error handling is applied.
func (rt *Router) Handle(pattern string, h Handler) {
	rt.mux.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
		rc := &RequestContext{
			DB:        rt.rc.DB,
			Logger:    rt.rc.Logger,
			TmplCache: rt.rc.TmplCache,
			IsAdmin:   rt.loadAuth(r),
		}

		handler := WithErrorHandling(rc, h)
		handler(w, r)
	})
}

// loadAuth checks if the request has a valid session cookie.
func (rt *Router) loadAuth(r *http.Request) bool {
	cookie, err := r.Cookie("session_id")
	if err != nil {
		return false
	}

	ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second)
	defer cancel()

	sess, err := session.QFindBySessionID(ctx, rt.rc.DB, cookie.Value)
	if err != nil {
		rt.rc.Logger.Error("failed to find session", slog.Any("err", err))
		return false
	}
	if sess == nil {
		return false
	}

	if time.Now().After(sess.ExpiresAt) {
		rt.rc.Logger.Info("session expired", slog.String("session_id", cookie.Value))
		return false
	}

	return true
}

// HandleStd registers a standard http.Handler (for static files, etc.)
func (rt *Router) HandleStd(pattern string, h http.Handler) {
	rt.mux.Handle(pattern, h)
}

func (rt *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	rt.mux.ServeHTTP(w, r)
}
