package utils

import (
	"encoding/json"
	"fmt"
	"log/slog"
	"net/http"
)

// APIError represents an API error with status code and message
type APIError struct {
	StatusCode int `json:"statusCode"`
	Msg        any `json:"msg"`
}

// Error implements the error interface for APIError
func (e APIError) Error() string {
	return fmt.Sprintf("api error: %d", e.StatusCode)
}

// NewAPIError creates a new APIError with the given status code and error message
func NewAPIError(statusCode int, err error) APIError {
	return APIError{
		StatusCode: statusCode,
		Msg:        err.Error(),
	}
}

// InvalidRequestData creates an APIError for validation errors with a map of field errors
func InvalidRequestData(msg string) APIError {
	return APIError{
		StatusCode: http.StatusUnprocessableEntity,
		Msg:        msg,
	}
}

// InvalidJSON creates an APIError for invalid JSON format
func InvalidJSON() APIError {
	return NewAPIError(http.StatusBadRequest, fmt.Errorf("invalid JSON request data"))
}

// APIResponse represents a standardized API response wrapper
type APIResponse struct {
	Success bool `json:"success"`
	Data    any  `json:"data,omitempty"`
	Error   any  `json:"error,omitempty"`
}

// WriteJSON writes the response as JSON with given status code, wrapped in a data object
func WriteJSON(w http.ResponseWriter, status int, data any) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(status)

	response := APIResponse{
		Success: status >= 200 && status < 300,
	}

	if response.Success {
		response.Data = data
	} else {
		response.Error = data
	}

	json.NewEncoder(w).Encode(response)
}

// APIFunc is the signature for API handler functions
type APIFunc func(w http.ResponseWriter, r *http.Request) error

// Make wraps an APIFunc and handles errors consistently
func Make(h APIFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if err := h(w, r); err != nil {
			if apiErr, ok := err.(APIError); ok {
				WriteJSON(w, apiErr.StatusCode, apiErr)
			} else {
				errResp := map[string]any{
					"statusCode": http.StatusInternalServerError,
					"msg":        "internal server error",
				}
				WriteJSON(w, http.StatusInternalServerError, errResp)
				// You could add logging here
				slog.Error("HTTP API error", "err", err.Error(), "path", r.URL.Path)
			}
		}
	}
}
