package api

import (
	"encoding/json"
	"net/http"
	"time"

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

// Response is the standard envelope for all API responses.
type Response struct {
	Data  any    `json:"data,omitempty"`
	Error *Error `json:"error,omitempty"`
	Meta  Meta   `json:"meta"`
}

// Error represents an API error.
type Error struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Details []any  `json:"details,omitempty"`
}

// Meta contains response metadata.
type Meta struct {
	RequestID string `json:"request_id,omitempty"`
	Timestamp string `json:"timestamp"`
}

// newMeta creates a Meta with current timestamp and request ID from context.
func newMeta(r *http.Request) Meta {
	return Meta{
		RequestID: middleware.GetReqID(r.Context()),
		Timestamp: time.Now().UTC().Format(time.RFC3339),
	}
}

// WriteJSON writes a JSON response with the given status code.
func WriteJSON(w http.ResponseWriter, r *http.Request, status int, data any) {
	resp := Response{
		Data: data,
		Meta: newMeta(r),
	}
	writeResponse(w, status, resp)
}

// WriteSuccess writes a successful JSON response with status 200 OK.
func WriteSuccess(w http.ResponseWriter, r *http.Request, data any) {
	WriteJSON(w, r, http.StatusOK, data)
}

// WriteCreated writes a successful JSON response with status 201 Created.
func WriteCreated(w http.ResponseWriter, r *http.Request, data any) {
	WriteJSON(w, r, http.StatusCreated, data)
}

// WriteNoContent writes a successful response with status 204 No Content.
func WriteNoContent(w http.ResponseWriter) {
	w.WriteHeader(http.StatusNoContent)
}

// WriteError writes an error response with the given status code.
func WriteError(w http.ResponseWriter, r *http.Request, status int, code, message string, details ...any) {
	resp := Response{
		Error: &Error{
			Code:    code,
			Message: message,
			Details: details,
		},
		Meta: newMeta(r),
	}
	writeResponse(w, status, resp)
}

// WriteBadRequest writes a 400 Bad Request error response.
func WriteBadRequest(w http.ResponseWriter, r *http.Request, message string, details ...any) {
	WriteError(w, r, http.StatusBadRequest, "BAD_REQUEST", message, details...)
}

// WriteNotFound writes a 404 Not Found error response.
func WriteNotFound(w http.ResponseWriter, r *http.Request, message string) {
	WriteError(w, r, http.StatusNotFound, "NOT_FOUND", message)
}

// WriteUnauthorized writes a 401 Unauthorized error response.
func WriteUnauthorized(w http.ResponseWriter, r *http.Request, message string) {
	WriteError(w, r, http.StatusUnauthorized, "UNAUTHORIZED", message)
}

// WriteForbidden writes a 403 Forbidden error response.
func WriteForbidden(w http.ResponseWriter, r *http.Request, message string) {
	WriteError(w, r, http.StatusForbidden, "FORBIDDEN", message)
}

// WriteInternalError writes a 500 Internal Server Error response.
func WriteInternalError(w http.ResponseWriter, r *http.Request, message string) {
	WriteError(w, r, http.StatusInternalServerError, "INTERNAL_ERROR", message)
}

// writeResponse marshals and writes the response.
func writeResponse(w http.ResponseWriter, status int, resp Response) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	w.WriteHeader(status)

	if err := json.NewEncoder(w).Encode(resp); err != nil {
		return
	}
}
