package apivalidate

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

	"github.com/ultisuite/ulti-backend/internal/api/apiresponse"
	"github.com/ultisuite/ulti-backend/internal/api/query"
)

// FieldDetail identifies a single invalid request field.
type FieldDetail struct {
	Field   string `json:"field"`
	Message string `json:"message"`
}

// ValidationError reports invalid request bodies using field-level details.
type ValidationError struct {
	Details []FieldDetail
}

func (e *ValidationError) Error() string {
	return "invalid request body"
}

// NewValidationError builds a validation error from field details.
func NewValidationError(details ...FieldDetail) *ValidationError {
	return &ValidationError{Details: details}
}

// DecodeJSON reads and decodes a JSON body with a size cap.
func DecodeJSON(w http.ResponseWriter, r *http.Request, limit int64, dest any) error {
	r.Body = http.MaxBytesReader(w, r.Body, limit)
	if err := json.NewDecoder(r.Body).Decode(dest); err != nil {
		var maxBytesErr *http.MaxBytesError
		if errors.As(err, &maxBytesErr) {
			apiresponse.WriteError(w, r, http.StatusRequestEntityTooLarge, apiresponse.CodePayloadTooLarge, "request body too large", nil)
			return err
		}
		apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidRequest, "invalid request body", nil)
		return err
	}
	return nil
}

// WriteValidationError writes a standardized validation error response.
func WriteValidationError(w http.ResponseWriter, r *http.Request, err *ValidationError) {
	apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidRequest, "invalid request body", err.Details)
}

// WriteQueryError maps query validation errors to API responses.
func WriteQueryError(w http.ResponseWriter, r *http.Request, err error) bool {
	var qerr *query.ValidationError
	if errors.As(err, &qerr) {
		apiresponse.WriteError(w, r, http.StatusBadRequest, qerr.Code, qerr.Message, qerr.Details)
		return true
	}
	apiresponse.WriteError(w, r, http.StatusBadRequest, apiresponse.CodeInvalidQueryParam, "invalid query parameters", nil)
	return true
}

// WriteNotFound writes a standardized not-found response.
func WriteNotFound(w http.ResponseWriter, r *http.Request, message string) {
	if message == "" {
		message = "not found"
	}
	apiresponse.WriteError(w, r, http.StatusNotFound, apiresponse.CodeNotFound, message, nil)
}

// WriteInternal writes a standardized internal error response.
func WriteInternal(w http.ResponseWriter, r *http.Request) {
	apiresponse.WriteError(w, r, http.StatusInternalServerError, apiresponse.CodeInternal, "internal error", nil)
}
