package gemini

import (
	"errors"
	"strings"
)

// Sentinel errors for common error types
var (
	// ErrInvalidConfig indicates configuration validation failed
	ErrInvalidConfig = errors.New("invalid configuration")

	// ErrRateLimit indicates rate limit exceeded
	ErrRateLimit = errors.New("rate limit exceeded")

	// ErrServerError indicates server-side error
	ErrServerError = errors.New("server error")

	// ErrInvalidRequest indicates client error
	ErrInvalidRequest = errors.New("invalid request")

	// ErrTimeout indicates request timeout
	ErrTimeout = errors.New("request timeout")

	// ErrUnauthorized indicates authentication failed
	ErrUnauthorized = errors.New("unauthorized")

	// ErrQuotaExceeded indicates quota has been exceeded
	ErrQuotaExceeded = errors.New("quota exceeded")

	// ErrContentBlocked indicates content was blocked by safety filters
	ErrContentBlocked = errors.New("content blocked by safety filters")
)

// classifyError attempts to classify an error from the Gemini API
// into one of our sentinel errors
func classifyError(err error) error {
	if err == nil {
		return nil
	}

	errStr := strings.ToLower(err.Error())

	// Check for rate limiting
	if strings.Contains(errStr, "rate limit") ||
		strings.Contains(errStr, "resource exhausted") ||
		strings.Contains(errStr, "too many requests") {
		return errors.Join(ErrRateLimit, err)
	}

	// Check for quota exceeded
	if strings.Contains(errStr, "quota") ||
		strings.Contains(errStr, "billing") {
		return errors.Join(ErrQuotaExceeded, err)
	}

	// Check for authentication errors
	if strings.Contains(errStr, "unauthorized") ||
		strings.Contains(errStr, "unauthenticated") ||
		strings.Contains(errStr, "invalid api key") ||
		strings.Contains(errStr, "permission denied") {
		return errors.Join(ErrUnauthorized, err)
	}

	// Check for content blocked
	if strings.Contains(errStr, "blocked") ||
		strings.Contains(errStr, "safety") ||
		strings.Contains(errStr, "harmful") {
		return errors.Join(ErrContentBlocked, err)
	}

	// Check for timeout
	if strings.Contains(errStr, "timeout") ||
		strings.Contains(errStr, "deadline exceeded") {
		return errors.Join(ErrTimeout, err)
	}

	// Check for server errors
	if strings.Contains(errStr, "internal") ||
		strings.Contains(errStr, "unavailable") ||
		strings.Contains(errStr, "server error") {
		return errors.Join(ErrServerError, err)
	}

	// Check for invalid request
	if strings.Contains(errStr, "invalid") ||
		strings.Contains(errStr, "bad request") ||
		strings.Contains(errStr, "malformed") {
		return errors.Join(ErrInvalidRequest, err)
	}

	// Return original error if no classification matches
	return err
}

// IsRateLimitError checks if the error is a rate limit error
func IsRateLimitError(err error) bool {
	return errors.Is(err, ErrRateLimit)
}

// IsQuotaExceededError checks if the error is a quota exceeded error
func IsQuotaExceededError(err error) bool {
	return errors.Is(err, ErrQuotaExceeded)
}

// IsUnauthorizedError checks if the error is an unauthorized error
func IsUnauthorizedError(err error) bool {
	return errors.Is(err, ErrUnauthorized)
}

// IsContentBlockedError checks if the error is a content blocked error
func IsContentBlockedError(err error) bool {
	return errors.Is(err, ErrContentBlocked)
}

// IsTimeoutError checks if the error is a timeout error
func IsTimeoutError(err error) bool {
	return errors.Is(err, ErrTimeout)
}

// IsServerError checks if the error is a server error
func IsServerError(err error) bool {
	return errors.Is(err, ErrServerError)
}

// IsRetryableError checks if the error should trigger a retry
func IsRetryableError(err error) bool {
	return errors.Is(err, ErrRateLimit) ||
		errors.Is(err, ErrServerError) ||
		errors.Is(err, ErrTimeout)
}
