package elinps

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

	"github.com/go-chi/chi/v5/middleware"
)

// LoggerPadrao cria um logger simples (stdout) adequado para Docker.
//
// Regras do projeto:
// - logs relevantes (rotas, tempo de execução, erros)
// - NUNCA logar segredos (Authorization/cookies/senha/DSN)
func LoggerPadrao() *slog.Logger {
	return slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
}

type responseWriterComStatus struct {
	http.ResponseWriter
	status int
	bytes  int
}

func (w *responseWriterComStatus) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *responseWriterComStatus) Write(b []byte) (int, error) {
	if w.status == 0 {
		w.status = http.StatusOK
	}
	n, err := w.ResponseWriter.Write(b)
	w.bytes += n
	return n, err
}

// MiddlewareLogRequisicao registra uma linha por requisição com:
// - método, path, status, duração
// - request_id (se existir)
// - ip_real (após chi/middleware.RealIP)
func MiddlewareLogRequisicao(logger *slog.Logger) func(http.Handler) http.Handler {
	if logger == nil {
		logger = slog.Default()
	}

	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			ini := time.Now()
			ww := &responseWriterComStatus{ResponseWriter: w}
			next.ServeHTTP(ww, r)

			dur := time.Since(ini)
			attrs := []any{
				"metodo", r.Method,
				"path", r.URL.Path,
				"status", ww.status,
				"dur_ms", dur.Milliseconds(),
				"bytes", ww.bytes,
				"ip_real", ipSomenteHost(r.RemoteAddr),
			}
			if reqID := requestIDFromContext(r.Context()); reqID != "" {
				attrs = append(attrs, "request_id", reqID)
			}
			logger.Info("http_request", attrs...)
		})
	}
}

// ipSomenteHost retorna apenas o IP (sem porta). Se o valor não parecer um IP,
// devolve string vazia.
func ipSomenteHost(remoteAddr string) string {
	ip := remoteAddr
	if host, _, err := net.SplitHostPort(remoteAddr); err == nil {
		ip = host
	}
	if net.ParseIP(ip) == nil {
		return ""
	}
	return ip
}

func requestIDFromContext(ctx context.Context) string {
	// O chi/middleware.RequestID coloca o ID no context.
	return middleware.GetReqID(ctx)
}
