package telemetry

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

type statusRecorder struct {
	http.ResponseWriter
	status int
}

func (r *statusRecorder) WriteHeader(code int) {
	r.status = code
	r.ResponseWriter.WriteHeader(code)
}

func skipAccessLog(path string) bool {
	switch path {
	case "/healthz", "/readyz":
		return true
	default:
		return false
	}
}

// HTTPMiddleware adds panic recovery, access logging, and server-error recording.
func HTTPMiddleware(logger *slog.Logger, next http.Handler) http.Handler {
	if logger == nil {
		return next
	}

	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		recorder := &statusRecorder{ResponseWriter: w, status: http.StatusOK}

		defer func() {
			if recovered := recover(); recovered != nil {
				RecordPanic(logger, "http", recovered)
				if recorder.status < http.StatusInternalServerError {
					http.Error(recorder, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
				}
			}

			if skipAccessLog(r.URL.Path) {
				return
			}

			attrs := []any{
				"method", r.Method,
				"path", r.URL.Path,
				"status", recorder.status,
				"duration_ms", time.Since(start).Milliseconds(),
			}
			if recorder.status >= http.StatusInternalServerError {
				RecordError(logger, fmtServerError(recorder.status), "http request failed", attrs...)
				return
			}
			logger.Info("http request", attrs...)
		}()

		next.ServeHTTP(recorder, r)
	})
}

type serverError struct {
	status int
}

func (e serverError) Error() string {
	return http.StatusText(e.status)
}

func fmtServerError(status int) error {
	return serverError{status: status}
}
