package web

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

	chimw "github.com/go-chi/chi/v5/middleware"
	"github.com/google/uuid"
)

// ctxKey is the unexported type used for context.Context keys owned by the
// web package. Per Go convention, using an unexported named type prevents
// accidental collisions with other packages' context keys.
type ctxKey string

const requestIDKey ctxKey = "request_id"

// RequestIDMiddleware emits a UUIDv4 for each request, attaches it to the
// request context under requestIDKey, and sets the X-Request-ID response
// header. The downstream handler (and any nested middleware) can recover
// the ID via LoggerFromContext for structured logging.
func RequestIDMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		id := uuid.NewString()
		ctx := context.WithValue(r.Context(), requestIDKey, id)
		w.Header().Set("X-Request-ID", id)
		next.ServeHTTP(w, r.WithContext(ctx))
	})
}

// LoggerFromContext returns slog.Default() decorated with the request_id
// attribute if one is present in ctx, otherwise plain slog.Default().
// Handlers should prefer this helper over slog.Default() so per-request
// log lines carry the request_id correlator.
func LoggerFromContext(ctx context.Context) *slog.Logger {
	if id, ok := ctx.Value(requestIDKey).(string); ok && id != "" {
		return slog.Default().With("request_id", id)
	}
	return slog.Default()
}

// SlogLoggerMiddleware returns chi-compatible middleware that emits one
// structured log line per request. The line carries method, path, status,
// duration_ms, and request_id (when present). Per RESEARCH Pitfall 6 this
// REPLACES chi's built-in middleware.Logger — never register both.
//
// The middleware deliberately allowlists fields (V7 / T-01-09): it never
// logs request bodies, Authorization headers, Cookie headers, or the DSN.
func SlogLoggerMiddleware(logger *slog.Logger) func(http.Handler) http.Handler {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			start := time.Now()
			ww := chimw.NewWrapResponseWriter(w, r.ProtoMajor)
			next.ServeHTTP(ww, r)

			l := logger
			if id, ok := r.Context().Value(requestIDKey).(string); ok && id != "" {
				l = l.With("request_id", id)
			}
			l.Info("request",
				"method", r.Method,
				"path", r.URL.Path,
				"status", ww.Status(),
				"duration_ms", time.Since(start).Milliseconds(),
			)
		})
	}
}
