package httperror

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

// ErrorResponse represents an HTTP error response (legacy format)
type ErrorResponse struct {
	Error   string `json:"error"`
	Message string `json:"message"`
	Code    int    `json:"code"`
}

// ProblemDetail represents an RFC 9457 compliant error response
// See: https://datatracker.ietf.org/doc/html/rfc9457
type ProblemDetail struct {
	Type     string                 `json:"type"`               // URI reference identifying the problem type
	Title    string                 `json:"title"`              // Short, human-readable summary
	Status   int                    `json:"status"`             // HTTP status code
	Detail   string                 `json:"detail,omitempty"`   // Human-readable explanation
	Instance string                 `json:"instance,omitempty"` // URI reference identifying the specific occurrence
	Errors   map[string][]string    `json:"errors,omitempty"`   // Validation errors (extension field)
	Extra    map[string]interface{} `json:"-"`                  // Additional extension members
}

// WriteError writes an error response with pretty printing (legacy format)
func WriteError(w http.ResponseWriter, code int, message string) {
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)

	response := ErrorResponse{
		Error:   http.StatusText(code),
		Message: message,
		Code:    code,
	}

	encoder := json.NewEncoder(w)
	encoder.SetIndent("", "  ")
	encoder.Encode(response)
}

// WriteProblemDetail writes an RFC 9457 compliant error response
func WriteProblemDetail(w http.ResponseWriter, problem *ProblemDetail) {
	w.Header().Set("Content-Type", "application/problem+json")
	w.WriteHeader(problem.Status)

	encoder := json.NewEncoder(w)
	encoder.SetIndent("", "  ")
	encoder.Encode(problem)
}

// BadRequest writes a 400 error
func BadRequest(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusBadRequest, message)
}

// Unauthorized writes a 401 error
func Unauthorized(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusUnauthorized, message)
}

// Forbidden writes a 403 error
func Forbidden(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusForbidden, message)
}

// NotFound writes a 404 error
func NotFound(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusNotFound, message)
}

// Conflict writes a 409 error
func Conflict(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusConflict, message)
}

// TooManyRequests writes a 429 error
func TooManyRequests(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusTooManyRequests, message)
}

// InternalServerError writes a 500 error
func InternalServerError(w http.ResponseWriter, message string) {
	WriteError(w, http.StatusInternalServerError, message)
}

// ValidationError writes an RFC 9457 validation error response (400)
func ValidationError(w http.ResponseWriter, errors map[string][]string, detail string) {
	if detail == "" {
		detail = "One or more validation errors occurred"
	}

	problem := &ProblemDetail{
		Type:   "about:blank", // Using about:blank as per RFC 9457 when no specific problem type URI is defined
		Title:  "Validation Error",
		Status: http.StatusBadRequest,
		Detail: detail,
		Errors: errors,
	}

	WriteProblemDetail(w, problem)
}

// ProblemBadRequest writes an RFC 9457 bad request error (400)
func ProblemBadRequest(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Bad Request",
		Status: http.StatusBadRequest,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemUnauthorized writes an RFC 9457 unauthorized error (401)
func ProblemUnauthorized(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Unauthorized",
		Status: http.StatusUnauthorized,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemForbidden writes an RFC 9457 forbidden error (403)
func ProblemForbidden(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Forbidden",
		Status: http.StatusForbidden,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemNotFound writes an RFC 9457 not found error (404)
func ProblemNotFound(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Not Found",
		Status: http.StatusNotFound,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemConflict writes an RFC 9457 conflict error (409)
func ProblemConflict(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Conflict",
		Status: http.StatusConflict,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemTooManyRequests writes an RFC 9457 too many requests error (429)
func ProblemTooManyRequests(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Too Many Requests",
		Status: http.StatusTooManyRequests,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}

// ProblemInternalServerError writes an RFC 9457 internal server error (500)
func ProblemInternalServerError(w http.ResponseWriter, detail string) {
	problem := &ProblemDetail{
		Type:   "about:blank",
		Title:  "Internal Server Error",
		Status: http.StatusInternalServerError,
		Detail: detail,
	}

	WriteProblemDetail(w, problem)
}
