package middleware

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

	"github.com/labstack/echo/v5"
)

// ErrorResponse represents a standardized error response
type ErrorResponse struct {
	Error   string `json:"error"`
	Message string `json:"message,omitempty"`
	Code    string `json:"code,omitempty"`
}

// HTTPError represents an HTTP error with additional context
type HTTPError struct {
	Code    int
	Message string
	Err     error
}

// Error implements the error interface
func (e *HTTPError) Error() string {
	if e.Err != nil {
		return fmt.Sprintf("%s: %v", e.Message, e.Err)
	}
	return e.Message
}

// Common error types
var (
	ErrBadRequest     = &HTTPError{Code: http.StatusBadRequest, Message: "Bad request"}
	ErrUnauthorized   = &HTTPError{Code: http.StatusUnauthorized, Message: "Unauthorized"}
	ErrForbidden      = &HTTPError{Code: http.StatusForbidden, Message: "Forbidden"}
	ErrNotFound       = &HTTPError{Code: http.StatusNotFound, Message: "Resource not found"}
	ErrConflict       = &HTTPError{Code: http.StatusConflict, Message: "Resource conflict"}
	ErrTooManyRequest = &HTTPError{Code: http.StatusTooManyRequests, Message: "Too many requests"}
	ErrInternal       = &HTTPError{Code: http.StatusInternalServerError, Message: "Internal server error"}
)

// NewHTTPError creates a new HTTP error
func NewHTTPError(code int, message string, err error) *HTTPError {
	return &HTTPError{
		Code:    code,
		Message: message,
		Err:     err,
	}
}

// RespondWithError sends a standardized error response
func RespondWithError(c *echo.Context, code int, message string, err error) error {
	response := ErrorResponse{
		Error:   message,
		Message: "",
		Code:    "",
	}

	// Include original error message in development mode if available
	if err != nil {
		response.Message = err.Error()
	}

	return c.JSON(code, response)
}

// RespondWithHTTPError sends an HTTPError as JSON
func RespondWithHTTPError(c *echo.Context, httpErr *HTTPError) error {
	response := ErrorResponse{
		Error: httpErr.Message,
	}

	if httpErr.Err != nil {
		response.Message = httpErr.Err.Error()
	}

	return c.JSON(httpErr.Code, response)
}

// WrapHandler wraps an echo.HandlerFunc to return standardized errors
func WrapHandler(fn func(*echo.Context) error) echo.HandlerFunc {
	return func(c *echo.Context) error {
		err := fn(c)
		if err != nil {
			if httpErr, ok := errors.AsType[*HTTPError](err); ok {
				return RespondWithHTTPError(c, httpErr)
			}
			return RespondWithError(c, http.StatusInternalServerError, "Internal server error", err)
		}
		return nil
	}
}
