package utils

import (
	"io"
	"net/http"
	"os"
	"runtime/debug"
	"time"

	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"

	"github.com/treytartt/honeydue-api/internal/dto/responses"
)

// InitLogger initializes the zerolog logger
func InitLogger(debug bool) {
	InitLoggerWithWriter(debug, nil)
}

// InitLoggerWithWriter initializes the zerolog logger with an optional additional writer
// The additional writer receives JSON formatted logs (useful for monitoring)
func InitLoggerWithWriter(debug bool, additionalWriter io.Writer) {
	zerolog.TimeFieldFormat = time.RFC3339

	if debug {
		zerolog.SetGlobalLevel(zerolog.DebugLevel)
	} else {
		zerolog.SetGlobalLevel(zerolog.InfoLevel)
	}

	// Build the output writer(s)
	var output io.Writer

	if additionalWriter != nil {
		// Always write JSON to additional writer for monitoring
		// The additional writer parses JSON to extract log entries
		if debug {
			// In debug mode: pretty console to stdout + JSON to additional writer
			consoleOutput := zerolog.ConsoleWriter{
				Out:        os.Stdout,
				TimeFormat: "15:04:05",
			}
			output = io.MultiWriter(consoleOutput, additionalWriter)
		} else {
			// In production: JSON to both stdout and additional writer
			output = io.MultiWriter(os.Stdout, additionalWriter)
		}
	} else {
		if debug {
			output = zerolog.ConsoleWriter{
				Out:        os.Stdout,
				TimeFormat: "15:04:05",
			}
		} else {
			output = os.Stdout
		}
	}

	log.Logger = zerolog.New(output).With().Timestamp().Caller().Logger()
}

// EchoLogger returns an Echo middleware for request logging
func EchoLogger() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			start := time.Now()
			req := c.Request()
			path := req.URL.Path
			raw := req.URL.RawQuery

			// Process request
			err := next(c)

			// Log after request
			end := time.Now()
			latency := end.Sub(start)

			if raw != "" {
				path = path + "?" + raw
			}

			res := c.Response()
			statusCode := res.Status

			msg := "Request"
			if err != nil {
				msg = err.Error()
			}

			event := log.Info()

			if statusCode >= 400 && statusCode < 500 {
				event = log.Warn()
			} else if statusCode >= 500 {
				event = log.Error()
			}

			event.
				Str("method", req.Method).
				Str("path", path).
				Int("status", statusCode).
				Str("ip", c.RealIP()).
				Dur("latency", latency).
				Str("user-agent", req.UserAgent()).
				Msg(msg)

			return err
		}
	}
}

// EchoRecovery returns an Echo middleware for panic recovery
func EchoRecovery() echo.MiddlewareFunc {
	return func(next echo.HandlerFunc) echo.HandlerFunc {
		return func(c echo.Context) error {
			defer func() {
				if err := recover(); err != nil {
					// F-14: Include full stack trace for debugging
					log.Error().
						Interface("error", err).
						Str("path", c.Request().URL.Path).
						Str("method", c.Request().Method).
						Str("stack", string(debug.Stack())).
						Msg("Panic recovered")

					// F-15: Use the project's standard ErrorResponse struct
					c.JSON(http.StatusInternalServerError, responses.ErrorResponse{
						Error: "Internal server error",
					})
				}
			}()

			return next(c)
		}
	}
}
