package routing

import (
	"errors"
	"strings"
)

// FailureType categorizes errors for cooldown duration selection.
type FailureType int

const (
	// FailureTypeNone indicates the error doesn't warrant a cooldown.
	// Examples: content blocked, invalid request, timeout.
	FailureTypeNone FailureType = iota

	// FailureTypeRateLimit indicates rate limiting or quota exhaustion.
	// Uses long cooldown (DefaultCooldownPeriod).
	// Examples: HTTP 429, quota_exceeded, resource_exhausted.
	FailureTypeRateLimit

	// FailureTypeTransient indicates transient server errors.
	// Uses short cooldown (TransientCooldownPeriod).
	// Examples: HTTP 500, 503, server unavailable, overloaded.
	FailureTypeTransient
)

// String returns a human-readable name for the failure type.
func (f FailureType) String() string {
	switch f {
	case FailureTypeNone:
		return "none"
	case FailureTypeRateLimit:
		return "rate-limit"
	case FailureTypeTransient:
		return "transient"
	default:
		return "unknown"
	}
}

// ClassifyError determines the failure type for cooldown selection.
//
// Returns:
//   - FailureTypeRateLimit for 429/quota errors (long cooldown)
//   - FailureTypeTransient for 5xx errors (short cooldown)
//   - FailureTypeNone for errors that don't warrant cooldown
//
// The function checks wrapped sentinel errors first (using errors.Is),
// then falls back to error message pattern matching for untyped errors.
func ClassifyError(err error) FailureType {
	if err == nil {
		return FailureTypeNone
	}

	// Check wrapped sentinel errors first (most specific)
	if errors.Is(err, ErrRateLimit) || errors.Is(err, ErrQuotaExceeded) {
		return FailureTypeRateLimit
	}
	if errors.Is(err, ErrServerUnavailable) {
		return FailureTypeTransient
	}

	// Pattern matching on error message for untyped errors
	errStr := strings.ToLower(err.Error())

	// Rate limit patterns (long cooldown)
	rateLimitPatterns := []string{
		"rate limit",
		"ratelimit",
		"too many requests",
		"429",
		"quota",
		"resource_exhausted",
	}
	for _, pattern := range rateLimitPatterns {
		if strings.Contains(errStr, pattern) {
			return FailureTypeRateLimit
		}
	}

	// Transient server error patterns (short cooldown)
	transientPatterns := []string{
		"503",
		"500",
		"unavailable",
		"overloaded",
		"service unavailable",
		"temporarily unavailable",
		"server error",
		"internal server error",
	}
	for _, pattern := range transientPatterns {
		if strings.Contains(errStr, pattern) {
			return FailureTypeTransient
		}
	}

	return FailureTypeNone
}

// IsRateLimitError returns true if the error indicates rate limiting.
func IsRateLimitError(err error) bool {
	return ClassifyError(err) == FailureTypeRateLimit
}

// IsTransientError returns true if the error is transient (quick recovery expected).
func IsTransientError(err error) bool {
	return ClassifyError(err) == FailureTypeTransient
}

// IsCooldownTriggeringError returns true if the error should trigger cooldown.
func IsCooldownTriggeringError(err error) bool {
	return ClassifyError(err) != FailureTypeNone
}
