package errors

import "fmt"

// ErrorCode représente un code d'erreur standardisé de l'application
type ErrorCode int

// AppError représente une erreur d'application avec un code standardisé
type AppError struct {
	Code    ErrorCode
	Message string
	Err     error
	Details []ErrorDetail
	Context map[string]interface{} // Contexte additionnel (request_id, user_id, etc.)
}

// ErrorDetail représente un détail d'erreur pour une validation
type ErrorDetail struct {
	Field   string `json:"field,omitempty"`
	Message string `json:"message"`
}

// Error implémente l'interface error
func (e *AppError) Error() string {
	if e.Err != nil {
		return fmt.Sprintf("[%d] %s: %v", e.Code, e.Message, e.Err)
	}
	return fmt.Sprintf("[%d] %s", e.Code, e.Message)
}

// Unwrap retourne l'erreur causale pour le support des errors.Is/errors.As
func (e *AppError) Unwrap() error {
	return e.Err
}

// New crée une nouvelle AppError avec un code et un message
func New(code ErrorCode, message string) *AppError {
	return &AppError{Code: code, Message: message}
}

// Wrap enveloppe une erreur existante dans une AppError
func Wrap(code ErrorCode, message string, err error) *AppError {
	return &AppError{Code: code, Message: message, Err: err}
}

// NewValidationError crée une nouvelle erreur de validation avec des détails
func NewValidationError(message string, details ...ErrorDetail) *AppError {
	return &AppError{
		Code:    ErrCodeValidation,
		Message: message,
		Details: details,
	}
}

// NewNotFoundError crée une nouvelle erreur "not found"
func NewNotFoundError(resource string) *AppError {
	return &AppError{
		Code:    ErrCodeNotFound,
		Message: fmt.Sprintf("%s not found", resource),
	}
}

// NewUnauthorizedError crée une nouvelle erreur d'autorisation
func NewUnauthorizedError(message string) *AppError {
	return &AppError{
		Code:    ErrCodeUnauthorized,
		Message: message,
	}
}

// NewForbiddenError crée une nouvelle erreur "forbidden"
func NewForbiddenError(message string) *AppError {
	return &AppError{
		Code:    ErrCodeForbidden,
		Message: message,
	}
}
