package notify

import (
	"errors"
	"fmt"
)

// Sentinel errors for programmatic handling.
var (
	ErrInvalidConfig = errors.New("invalid configuration")
	ErrUnauthorized  = errors.New("unauthorized")
	ErrForbidden     = errors.New("forbidden")
	ErrSuppressed    = errors.New("recipient suppressed")
	ErrHostNotFound  = errors.New("host not found")
	ErrFromNotFound  = errors.New("from address not registered")
	ErrValidation    = errors.New("validation error")
	ErrServerError   = errors.New("server error")
	ErrRateLimit     = errors.New("rate limit exceeded")
)

// APIError represents an error returned by the notify API.
type APIError struct {
	StatusCode int
	Message    string
	Code       string
	err        error
}

func (e *APIError) Error() string {
	if e.Code != "" {
		return fmt.Sprintf("notify api error (status %d): [%s] %s", e.StatusCode, e.Code, e.Message)
	}
	return fmt.Sprintf("notify api error (status %d): %s", e.StatusCode, e.Message)
}

func (e *APIError) Unwrap() error {
	return e.err
}

// classifyError maps an HTTP status and optional error code to a sentinel error.
func classifyError(statusCode int, code string) error {
	// Check specific error codes first.
	switch code {
	case "suppressed":
		return ErrSuppressed
	case "host_not_found":
		return ErrHostNotFound
	case "from_not_found":
		return ErrFromNotFound
	}

	// Fall back to HTTP status.
	switch {
	case statusCode == 401:
		return ErrUnauthorized
	case statusCode == 403:
		return ErrForbidden
	case statusCode == 422:
		return ErrValidation
	case statusCode == 429:
		return ErrRateLimit
	case statusCode >= 400 && statusCode < 500:
		return ErrValidation
	case statusCode >= 500:
		return ErrServerError
	default:
		return nil
	}
}
