package infra

import (
	"bufio"
	"fmt"
	"io"
	"net"
	"net/http"
	"time"
)

// responseWriter captura el status code escrito al ResponseWriter.
// Implementa http.Hijacker y http.Flusher delegando al writer subyacente
// para preservar WebSocket upgrade y SSE.
type responseWriter struct {
	http.ResponseWriter
	status int
}

func (rw *responseWriter) WriteHeader(status int) {
	rw.status = status
	rw.ResponseWriter.WriteHeader(status)
}

// Hijack delega en el ResponseWriter subyacente si lo soporta. Necesario
// para que WebSocket Upgrade funcione a traves del logger middleware.
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if h, ok := rw.ResponseWriter.(http.Hijacker); ok {
		return h.Hijack()
	}
	return nil, nil, http.ErrNotSupported
}

// Flush delega en el ResponseWriter subyacente si lo soporta. Necesario
// para SSE y respuestas streaming.
func (rw *responseWriter) Flush() {
	if f, ok := rw.ResponseWriter.(http.Flusher); ok {
		f.Flush()
	}
}

// HTTPLoggerMiddleware retorna un Middleware que loguea metodo, path, status y duracion de cada request.
// El formato de cada linea es: METHOD /path STATUS DURACIONms
func HTTPLoggerMiddleware(logger io.Writer) Middleware {
	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			start := time.Now()
			rw := &responseWriter{ResponseWriter: w, status: http.StatusOK}
			next.ServeHTTP(rw, r)
			duration := time.Since(start)
			fmt.Fprintf(logger, "%s %s %d %dms\n",
				r.Method, r.URL.Path, rw.status, duration.Milliseconds())
		})
	}
}
