package apperrors

import (
	"errors"
	"fmt"
	"net/http"

	"github.com/go-playground/validator/v10"
	"github.com/labstack/echo/v4"
	"github.com/rs/zerolog/log"

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

// HTTPErrorHandler handles all errors returned from handlers in a consistent way.
// It converts AppErrors, validation errors, and Echo HTTPErrors to JSON responses.
// This is the base handler - additional service-level error handling can be added in router.go.
func HTTPErrorHandler(err error, c echo.Context) {
	// Already committed? Skip
	if c.Response().Committed {
		return
	}

	// Handle AppError (our custom application errors)
	var appErr *AppError
	if errors.As(err, &appErr) {
		message := i18n.LocalizedMessage(c, appErr.MessageKey)
		// If i18n key not found (returns the key itself), use fallback message
		if message == appErr.MessageKey && appErr.Message != "" {
			message = appErr.Message
		} else if message == appErr.MessageKey {
			message = appErr.MessageKey // Use the key as last resort
		}

		// Log internal errors
		if appErr.Err != nil {
			log.Error().Err(appErr.Err).Str("message_key", appErr.MessageKey).Msg("Application error")
		}

		c.JSON(appErr.Code, responses.ErrorResponse{Error: message})
		return
	}

	// Handle validation errors from go-playground/validator
	var validationErrs validator.ValidationErrors
	if errors.As(err, &validationErrs) {
		c.JSON(http.StatusBadRequest, customvalidator.FormatValidationErrors(err))
		return
	}

	// Handle Echo's built-in HTTPError
	var httpErr *echo.HTTPError
	if errors.As(err, &httpErr) {
		msg := fmt.Sprintf("%v", httpErr.Message)
		c.JSON(httpErr.Code, responses.ErrorResponse{Error: msg})
		return
	}

	// Default: Internal server error (don't expose error details to client)
	log.Error().Err(err).Msg("Unhandled error")
	c.JSON(http.StatusInternalServerError, responses.ErrorResponse{
		Error: i18n.LocalizedMessage(c, "error.internal"),
	})
}
