/**
 * Error categories for observability grouping and classification.
 * Used to categorize errors in the execution_errors table metadata.
 */
export type ExecutionErrorCategory = 'llm' | 'tool' | 'workflow' | 'agent' | 'validation' | 'system'

/**
 * Abstract base class for all execution engine errors.
 * Enforces contract for execution_errors table insertion with explicit type,
 * severity, category, and context properties.
 *
 * All execution engine errors MUST extend this class to ensure proper error
 * tracking and observability in the execution_errors table.
 *
 * @example
 * ```typescript
 * export class MyExecutionError extends ExecutionError {
 *   readonly type = 'my_execution_error' as const
 *   readonly severity = 'warning' as const
 *   readonly category = 'workflow' as const
 *
 *   constructor(message: string, context?: Record<string, unknown>) {
 *     super(message, context)
 *   }
 * }
 * ```
 */
export abstract class ExecutionError extends Error {
  /**
   * Error type identifier for execution_errors table.
   * Should be a unique, snake_case string that identifies this specific error class.
   * Used for filtering, aggregation, and error-specific handling in observability systems.
   */
  abstract readonly type: string

  /**
   * Error severity level for execution_errors table.
   * - critical: System failures, auth issues, resource exhaustion - execution cannot continue
   * - warning: Transient failures, configuration errors - execution may retry or requires user correction
   * - info: Validation failures, expected user errors - user/developer action needed
   */
  abstract readonly severity: 'critical' | 'warning' | 'info'

  /**
   * Error category for observability grouping.
   * Used to categorize errors in dashboards and analytics.
   */
  abstract readonly category: ExecutionErrorCategory

  /**
   * Additional context/metadata for the error.
   * Stored in execution_errors.metadata JSONB column.
   */
  public readonly context?: Record<string, unknown>

  /**
   * @param message - Human-readable error message
   * @param context - Additional context/metadata for observability
   */
  constructor(message: string, context?: Record<string, unknown>) {
    super(message)
    this.name = this.constructor.name
    this.context = context

    // Maintain proper stack trace for where our error was thrown
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, this.constructor)
    }
  }

  /**
   * Indicates whether this error type is retryable.
   * Default: false (safe default - only retry when explicitly safe to do so)
   *
   * Subclasses should override to return true for retryable scenarios:
   * - Network/infrastructure errors (exponential backoff)
   * - Rate limiting (linear backoff)
   * - Service availability (exponential backoff)
   * - Circuit breaker (circuit breaker's own delay)
   *
   * DO NOT retry:
   * - Authentication/authorization errors
   * - Validation errors
   * - Configuration errors
   * - Resource exhaustion errors
   */
  isRetryable(): boolean {
    return false
  }
}

/**
 * Unknown execution error - fallback for untyped errors
 *
 * Used when catching errors that are not ExecutionError instances.
 * Preserves original error context for debugging while ensuring
 * consistent error tracking in the execution_errors table.
 *
 * Severity: critical (unknown errors should be treated seriously until investigated)
 */
export class UnknownExecutionError extends ExecutionError {
  readonly type = 'unknown_execution_error' as const
  readonly severity = 'critical' as const
  readonly category = 'system' as const

  constructor(
    message: string,
    public readonly originalError?: unknown
  ) {
    super(message, {
      originalError: originalError instanceof Error ? {
        name: originalError.name,
        message: originalError.message,
        stack: originalError.stack
      } : originalError
    })
  }
}
