using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

using Newtonsoft.Json.Linq;

using AIRuntime.Runtime.Capabilities;
using AIRuntime.Runtime.Capabilities.Permissions;
using AIRuntime.Runtime.Core;
using AIRuntime.Runtime.Filesystem;
using AIRuntime.Runtime.Models;
using AIRuntime.Runtime.Providers;
using AIRuntime.Runtime.Providers.Fallback;
using AIRuntime.Runtime.Providers.Health;
using AIRuntime.Runtime.Providers.Models;
using AIRuntime.Runtime.Services.Agent;
using AIRuntime.Runtime.Tools;
using AIRuntime.Runtime.Agents.Runtime;

namespace AIRuntime.Runtime
{
    /// <summary>
    /// Main entry point into AIRuntime.
    /// Responsible for wiring together runtime services.
    /// </summary>
    public sealed class AIRuntime
    {
        private const string ProviderConfigurationLockedMessage =
            "Provider configuration cannot be changed while an agent run is in progress.";


        private const string ProviderHealthConfigurationLockedMessage =
            "Provider health configuration cannot be changed while an agent run is in progress.";


        private readonly CapabilityRegistry _capabilityRegistry;

        private readonly CapabilityDispatcher _capabilityDispatcher;

        private readonly CapabilitySchemaExporter _schemaExporter;

        private readonly AgentObserverCollection _agentObservers;

        private readonly IFileSystem _fileSystem;

        private readonly ToolCallParser _toolParser;

        private readonly ToolExecutor _toolExecutor;

        private readonly CapabilityPermissionPolicy _permissionPolicy;

        private readonly ProviderFallbackChain _providerChain;

        private readonly ProviderRetryPolicy _providerRetryPolicy;

        private readonly ProviderCooldownPolicy _providerCooldownPolicy;

        private readonly ProviderHealthTracker _providerHealthTracker;

        private readonly IProviderFailureClassifier _providerFailureClassifier;

        private readonly IProviderToolBuilder _providerToolBuilder;


        private ConversationEngine _engine;

        private ICapabilityApprovalHandler _approvalHandler;


        private TimeSpan _providerTimeout =
            TimeSpan.FromSeconds(
                60);


        private TimeSpan _runTimeout =
            TimeSpan.FromMinutes(
                5);


        private string _systemPrompt =
            string.Empty;


        private int _maxCapabilityRounds;


        public AIRuntime(
            string workspaceRoot)
            : this(
                workspaceRoot,
                composition: null)
        {
        }


        internal AIRuntime(
            string workspaceRoot,
            AIRuntimeCompositionOptions composition)
        {
            if (string.IsNullOrWhiteSpace(workspaceRoot))
            {
                throw new ArgumentException(
                    "Workspace path cannot be null or empty.",
                    nameof(workspaceRoot));
            }


            //--------------------------------------------------
            // Capability Registry
            //--------------------------------------------------

            _capabilityRegistry =
                new CapabilityRegistry();


            //--------------------------------------------------
            // Schema Exporter
            //--------------------------------------------------

            _schemaExporter =
                new CapabilitySchemaExporter();


            //--------------------------------------------------
            // Agent Observers
            //--------------------------------------------------

            _agentObservers =
                new AgentObserverCollection();


            if (composition?.IncludeConsoleObserver ?? true)
            {
                _agentObservers.Add(
                    new ConsoleAgentObserver());
            }

            if (composition?.Observers != null)
            {
                foreach (IAgentObserver observer in composition.Observers)
                {
                    _agentObservers.Add(
                        observer ??
                        throw new ArgumentException(
                            "Configured agent observers cannot contain null entries.",
                            nameof(composition)));
                }
            }


            //--------------------------------------------------
            // Workspace / File System
            //--------------------------------------------------

            if (composition?.FileSystem != null)
            {
                _fileSystem =
                    composition.FileSystem;
            }
            else
            {
                Workspace workspace =
                    new Workspace(
                        workspaceRoot);

                _fileSystem =
                    new LocalFileSystem(
                        workspace);
            }


            //--------------------------------------------------
            // Capability Permissions
            //--------------------------------------------------

            _permissionPolicy =
                new CapabilityPermissionPolicy();


            //--------------------------------------------------
            // Capability Dispatcher
            //--------------------------------------------------

            _capabilityDispatcher =
                new CapabilityDispatcher(
                    _capabilityRegistry,
                    _fileSystem,
                    _permissionPolicy,
                    composition?.Middleware,
                    composition?.IncludeDefaultMiddleware ?? true);


            //--------------------------------------------------
            // Tool Execution
            //--------------------------------------------------

            _toolParser =
                new ToolCallParser();


            _toolExecutor =
                new ToolExecutor(
                    _capabilityDispatcher);


            //--------------------------------------------------
            // Provider Fallback and Retry
            //--------------------------------------------------

            _providerChain =
                new ProviderFallbackChain();


            _providerRetryPolicy =
                new ProviderRetryPolicy();


            //--------------------------------------------------
            // Provider Health and Cooldown
            //--------------------------------------------------

            _providerCooldownPolicy =
                new ProviderCooldownPolicy();


            _providerHealthTracker =
                new ProviderHealthTracker(
                    _providerCooldownPolicy);


            _providerFailureClassifier =
                composition?.FailureClassifier ??
                new DefaultProviderFailureClassifier();


            _providerToolBuilder =
                composition?.ToolBuilder ??
                new ProviderToolBuilder();
        }


        //--------------------------------------------------
        // Agent State
        //--------------------------------------------------

        /// <summary>
        /// Returns the context belonging to the most recent
        /// or currently running agent request.
        /// </summary>
        public AgentRunContext LastRunContext
        {
            get
            {
                return _engine?.LastRunContext;
            }
        }


        /// <summary>
        /// Returns true while an agent request is executing.
        /// </summary>
        public bool IsRunning
        {
            get
            {
                return _engine?.IsRunning ??
                       false;
            }
        }


        /// <summary>
        /// Number of messages currently stored in the active
        /// persistent conversation.
        ///
        /// The system prompt is not included.
        /// </summary>
        public int MessageCount
        {
            get
            {
                return _engine?.MessageCount ??
                       0;
            }
        }


        //--------------------------------------------------
        // Capability Permissions
        //--------------------------------------------------

        public CapabilityPermissionDecision GetPermissionDecision(
            CapabilityPermission permission)
        {
            return _permissionPolicy.GetDecision(
                permission);
        }


        public void AllowPermission(
            CapabilityPermission permission)
        {
            ThrowIfRunning(
                "Capability permissions cannot be changed while an agent run is in progress.");


            _permissionPolicy.Allow(
                permission);
        }


        public void DenyPermission(
            CapabilityPermission permission)
        {
            ThrowIfRunning(
                "Capability permissions cannot be changed while an agent run is in progress.");


            _permissionPolicy.Deny(
                permission);
        }


        public void RequirePermissionApproval(
            CapabilityPermission permission)
        {
            ThrowIfRunning(
                "Capability permissions cannot be changed while an agent run is in progress.");


            _permissionPolicy.RequireApproval(
                permission);
        }


        public void ResetPermissionPolicy()
        {
            ThrowIfRunning(
                "Capability permissions cannot be changed while an agent run is in progress.");


            _permissionPolicy.ResetToDefaults();
        }


        //--------------------------------------------------
        // Capability Approval
        //--------------------------------------------------

        public bool HasApprovalHandler
        {
            get
            {
                return _approvalHandler != null;
            }
        }


        /// <summary>
        /// Configures the handler used when a capability
        /// requires explicit approval.
        ///
        /// Pass null to remove the current handler.
        /// </summary>
        public void SetApprovalHandler(
            ICapabilityApprovalHandler approvalHandler)
        {
            ThrowIfRunning(
                "The capability approval handler cannot be changed while an agent run is in progress.");


            _approvalHandler =
                approvalHandler;


            _capabilityDispatcher.SetApprovalHandler(
                approvalHandler);
        }


        public void ClearApprovalHandler()
        {
            SetApprovalHandler(
                null);
        }


        //--------------------------------------------------
        // System Prompt
        //--------------------------------------------------

        public string SystemPrompt
        {
            get
            {
                return _systemPrompt;
            }

            set
            {
                ThrowIfRunning(
                    "The system prompt cannot be changed while an agent run is in progress.");


                _systemPrompt =
                    value?.Trim() ??
                    string.Empty;


                if (_engine != null)
                {
                    _engine.SystemPrompt =
                        _systemPrompt;
                }
            }
        }


        public void ClearSystemPrompt()
        {
            ThrowIfRunning(
                "The system prompt cannot be changed while an agent run is in progress.");


            _systemPrompt =
                string.Empty;


            if (_engine != null)
            {
                _engine.ClearSystemPrompt();
            }
        }


        //--------------------------------------------------
        // Provider Timeout
        //--------------------------------------------------

        /// <summary>
        /// Maximum duration allowed for each individual
        /// provider attempt.
        /// </summary>
        public TimeSpan ProviderTimeout
        {
            get
            {
                return _providerTimeout;
            }

            set
            {
                if (value <= TimeSpan.Zero)
                {
                    throw new ArgumentOutOfRangeException(
                        nameof(value),
                        "Provider timeout must be greater than zero.");
                }


                ThrowIfRunning(
                    "The provider timeout cannot be changed while an agent run is in progress.");


                _providerTimeout =
                    value;


                if (_engine != null)
                {
                    _engine.ProviderTimeout =
                        value;
                }
            }
        }


        //--------------------------------------------------
        // Run Timeout
        //--------------------------------------------------

        /// <summary>
        /// Maximum duration allowed for an entire agent run,
        /// including retries, fallback providers, approvals,
        /// and capability execution. Use
        /// <see cref="Timeout.InfiniteTimeSpan"/> to disable the
        /// fixed total-duration limit.
        /// </summary>
        public TimeSpan RunTimeout
        {
            get
            {
                return _runTimeout;
            }

            set
            {
                if (value != Timeout.InfiniteTimeSpan &&
                    value <= TimeSpan.Zero)
                {
                    throw new ArgumentOutOfRangeException(
                        nameof(value),
                        "Run timeout must be greater than zero or Timeout.InfiniteTimeSpan.");
                }


                ThrowIfRunning(
                    "The run timeout cannot be changed while an agent run is in progress.");


                _runTimeout =
                    value;


                if (_engine != null)
                {
                    _engine.RunTimeout =
                        value;
                }
            }
        }


        //--------------------------------------------------
        // Provider Retry Configuration
        //--------------------------------------------------

        /// <summary>
        /// Number of additional attempts allowed per provider.
        ///
        /// Zero disables retries.
        /// </summary>
        public int ProviderRetryCount
        {
            get
            {
                return _providerRetryPolicy.MaxRetries;
            }

            set
            {
                ThrowIfRunning(
                    ProviderConfigurationLockedMessage);


                _providerRetryPolicy.MaxRetries =
                    value;
            }
        }


        public TimeSpan ProviderRetryDelay
        {
            get
            {
                return _providerRetryPolicy.InitialDelay;
            }

            set
            {
                ThrowIfRunning(
                    ProviderConfigurationLockedMessage);


                _providerRetryPolicy.InitialDelay =
                    value;
            }
        }


        public double ProviderRetryBackoffMultiplier
        {
            get
            {
                return _providerRetryPolicy.BackoffMultiplier;
            }

            set
            {
                ThrowIfRunning(
                    ProviderConfigurationLockedMessage);


                _providerRetryPolicy.BackoffMultiplier =
                    value;
            }
        }


        public TimeSpan ProviderMaximumRetryDelay
        {
            get
            {
                return _providerRetryPolicy.MaximumDelay;
            }

            set
            {
                ThrowIfRunning(
                    ProviderConfigurationLockedMessage);


                _providerRetryPolicy.MaximumDelay =
                    value;
            }
        }


        public void SetProviderFailureRetryable(
            ProviderFailureKind failureKind,
            bool retryable)
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            _providerRetryPolicy.SetRetryable(
                failureKind,
                retryable);
        }


        public bool IsProviderFailureRetryable(
            ProviderFailureKind failureKind)
        {
            return _providerRetryPolicy.ShouldRetry(
                failureKind);
        }


        public void ResetProviderRetryPolicy()
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            _providerRetryPolicy.ResetToDefaults();
        }


        //--------------------------------------------------
        // Provider Health Configuration
        //--------------------------------------------------

        /// <summary>
        /// Consecutive provider failures required before
        /// the provider enters cooldown.
        /// </summary>
        public int ProviderCooldownFailureThreshold
        {
            get
            {
                return _providerCooldownPolicy.FailureThreshold;
            }

            set
            {
                ThrowIfRunning(
                    ProviderHealthConfigurationLockedMessage);


                _providerCooldownPolicy.FailureThreshold =
                    value;
            }
        }


        /// <summary>
        /// Initial cooldown applied after the failure
        /// threshold is reached.
        /// </summary>
        public TimeSpan ProviderBaseCooldown
        {
            get
            {
                return _providerCooldownPolicy.BaseCooldown;
            }

            set
            {
                ThrowIfRunning(
                    ProviderHealthConfigurationLockedMessage);


                _providerCooldownPolicy.BaseCooldown =
                    value;
            }
        }


        /// <summary>
        /// Maximum cooldown duration allowed for a provider.
        /// </summary>
        public TimeSpan ProviderMaximumCooldown
        {
            get
            {
                return _providerCooldownPolicy.MaximumCooldown;
            }

            set
            {
                ThrowIfRunning(
                    ProviderHealthConfigurationLockedMessage);


                _providerCooldownPolicy.MaximumCooldown =
                    value;
            }
        }


        /// <summary>
        /// Multiplier applied to cooldown duration after
        /// additional consecutive failures.
        /// </summary>
        public double ProviderCooldownMultiplier
        {
            get
            {
                return _providerCooldownPolicy.CooldownMultiplier;
            }

            set
            {
                ThrowIfRunning(
                    ProviderHealthConfigurationLockedMessage);


                _providerCooldownPolicy.CooldownMultiplier =
                    value;
            }
        }


        /// <summary>
        /// Restores default cooldown settings.
        ///
        /// Existing provider health records are preserved.
        /// </summary>
        public void ResetProviderCooldownPolicy()
        {
            ThrowIfRunning(
                ProviderHealthConfigurationLockedMessage);


            _providerCooldownPolicy.ResetToDefaults();
        }


        //--------------------------------------------------
        // Provider Health Inspection
        //--------------------------------------------------

        /// <summary>
        /// Returns a snapshot of health information for a provider.
        /// </summary>
        public ProviderHealthRecord GetProviderHealth(
            IProvider provider)
        {
            return _providerHealthTracker.GetHealth(
                provider);
        }


        /// <summary>
        /// Returns health snapshots for all providers that have
        /// recorded attempts or have been inspected.
        /// </summary>
        public IReadOnlyList<ProviderHealthRecord> GetAllProviderHealth()
        {
            return _providerHealthTracker.GetAllHealth();
        }


        /// <summary>
        /// Returns true when the provider is not currently cooling down.
        /// </summary>
        public bool IsProviderAvailable(
            IProvider provider)
        {
            return _providerHealthTracker.IsAvailable(
                provider);
        }


        /// <summary>
        /// Clears health history for one provider.
        /// </summary>
        public void ResetProviderHealth(
            IProvider provider)
        {
            ThrowIfRunning(
                "Provider health cannot be reset while an agent run is in progress.");


            _providerHealthTracker.Reset(
                provider);
        }


        /// <summary>
        /// Clears health history for every provider.
        /// </summary>
        public void ResetAllProviderHealth()
        {
            ThrowIfRunning(
                "Provider health cannot be reset while an agent run is in progress.");


            _providerHealthTracker.ResetAll();
        }


        //--------------------------------------------------
        // Maximum Capability Rounds
        //--------------------------------------------------

        /// <summary>
        /// Optional fixed ceiling for model-driven capability rounds.
        /// Zero, the default, disables the fixed ceiling.
        /// </summary>
        public int MaxCapabilityRounds
        {
            get
            {
                return _maxCapabilityRounds;
            }

            set
            {
                if (value < 0)
                {
                    throw new ArgumentOutOfRangeException(
                        nameof(value),
                        "Maximum capability rounds cannot be negative. Use zero for no fixed limit.");
                }


                ThrowIfRunning(
                    "Maximum capability rounds cannot be changed while an agent run is in progress.");


                _maxCapabilityRounds =
                    value;


                if (_engine != null)
                {
                    _engine.MaxCapabilityRounds =
                        value;
                }
            }
        }


        //--------------------------------------------------
        // Conversation State
        //--------------------------------------------------

        public void ResetConversation()
        {
            ThrowIfRunning(
                "The conversation cannot be reset while an agent run is in progress.");


            _engine?.ResetConversation();
        }


        //--------------------------------------------------
        // Agent Observers
        //--------------------------------------------------

        public void AddAgentObserver(
            IAgentObserver observer)
        {
            if (observer == null)
            {
                throw new ArgumentNullException(
                    nameof(observer));
            }


            ThrowIfRunning(
                "Agent observers cannot be changed while an agent run is in progress.");


            _agentObservers.Add(
                observer);
        }


        public void RemoveAgentObserver(
            IAgentObserver observer)
        {
            if (observer == null)
                return;


            ThrowIfRunning(
                "Agent observers cannot be changed while an agent run is in progress.");


            _agentObservers.Remove(
                observer);
        }


        //--------------------------------------------------
        // Capability Registration
        //--------------------------------------------------

        public void RegisterCapability(
            ICapability capability)
        {
            if (capability == null)
            {
                throw new ArgumentNullException(
                    nameof(capability));
            }


            ThrowIfRunning(
                "Capabilities cannot be registered while an agent run is in progress.");


            _capabilityRegistry.Register(
                capability);
        }


        public IReadOnlyList<CapabilityDescriptor> GetCapabilities()
        {
            return _capabilityRegistry
                .GetDescriptors();
        }


        //--------------------------------------------------
        // Tool Schema Export
        //--------------------------------------------------

        public JArray ExportToolSchemas()
        {
            return _schemaExporter
                .ExportOpenAITools(
                    GetCapabilities());
        }


        public IReadOnlyList<ProviderTool> ExportProviderTools()
        {
            return _schemaExporter
                .ExportProviderTools(
                    _capabilityRegistry
                        .GetDescriptors());
        }


        //--------------------------------------------------
        // Direct Tool Execution
        //--------------------------------------------------

        public async Task<ToolCallResult> ExecuteToolCallAsync(
            string json)
        {
            ToolCallRequest request =
                _toolParser.Parse(
                    json);


            return await _toolExecutor
                .ExecuteAsync(
                    request);
        }


        public Task<string> ExecuteCapabilityAsync(
            string capabilityName,
            string jsonArguments)
        {
            return ExecuteCapabilityAsync(
                capabilityName,
                jsonArguments,
                CancellationToken.None);
        }


        public async Task<string> ExecuteCapabilityAsync(
            string capabilityName,
            string jsonArguments,
            CancellationToken cancellationToken)
        {
            if (string.IsNullOrWhiteSpace(capabilityName))
            {
                throw new ArgumentException(
                    "Capability name cannot be empty.",
                    nameof(capabilityName));
            }


            cancellationToken
                .ThrowIfCancellationRequested();


            ToolCall toolCall =
                new ToolCall
                {
                    Name =
                        capabilityName,

                    Arguments =
                        jsonArguments ??
                        string.Empty
                };


            return await _capabilityDispatcher
                .DispatchAsync(
                    toolCall,
                    sessionId: string.Empty,
                    cancellationToken);
        }


        //--------------------------------------------------
        // Primary Provider
        //--------------------------------------------------

        public bool HasProvider
        {
            get
            {
                return _providerChain.HasPrimaryProvider;
            }
        }


        public IProvider PrimaryProvider
        {
            get
            {
                return _providerChain.PrimaryProvider;
            }
        }


        public void UseProvider(
            IProvider provider)
        {
            if (provider == null)
            {
                throw new ArgumentNullException(
                    nameof(provider));
            }


            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            _providerChain.SetPrimaryProvider(
                provider);


            RebuildConversationEngine();
        }


        //--------------------------------------------------
        // Fallback Providers
        //--------------------------------------------------

        public int FallbackProviderCount
        {
            get
            {
                return _providerChain.FallbackCount;
            }
        }


        public void AddFallbackProvider(
            IProvider provider)
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            _providerChain.AddFallbackProvider(
                provider);
        }


        public void InsertFallbackProvider(
            int index,
            IProvider provider)
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            _providerChain.InsertFallbackProvider(
                index,
                provider);
        }


        public bool RemoveFallbackProvider(
            IProvider provider)
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            bool removed =
                _providerChain.RemoveFallbackProvider(
                    provider);


            if (removed)
            {
                _providerHealthTracker.Reset(
                    provider);
            }


            return removed;
        }


        public void RemoveFallbackProviderAt(
            int index)
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            IReadOnlyList<IProvider> fallbacks =
                _providerChain.GetFallbackProviders();


            IProvider provider =
                fallbacks[index];


            _providerChain.RemoveFallbackProviderAt(
                index);


            _providerHealthTracker.Reset(
                provider);
        }


        public void ClearFallbackProviders()
        {
            ThrowIfRunning(
                ProviderConfigurationLockedMessage);


            IReadOnlyList<IProvider> providers =
                _providerChain.GetFallbackProviders();


            _providerChain.ClearFallbackProviders();


            foreach (IProvider provider in providers)
            {
                _providerHealthTracker.Reset(
                    provider);
            }
        }


        public IReadOnlyList<IProvider> GetFallbackProviders()
        {
            return _providerChain
                .GetFallbackProviders();
        }


        public IReadOnlyList<IProvider> GetProvidersInPriorityOrder()
        {
            return _providerChain
                .GetProvidersInPriorityOrder();
        }


        //--------------------------------------------------
        // Text Response API
        //--------------------------------------------------

        public Task<string> ChatAsync(
            string prompt)
        {
            return ChatAsync(
                prompt,
                CancellationToken.None);
        }


        public Task<string> ChatAsync(
            string prompt,
            CancellationToken cancellationToken)
        {
            EnsureProviderConfigured();


            return _engine.ChatAsync(
                prompt,
                cancellationToken);
        }


//--------------------------------------------------
// Structured Agent Run API
//--------------------------------------------------

        public Task<AgentRunResult> RunAsync(
            string prompt)
        {
            return RunAsync(
                prompt,
                CancellationToken.None);
        }


        public Task<AgentRunResult> RunAsync(
            string prompt,
            CancellationToken cancellationToken)
        {
            EnsureProviderConfigured();


            return _engine.RunAsync(
                prompt,
                cancellationToken);
        }


        //--------------------------------------------------
        // Agent Runtime Execution
        //--------------------------------------------------

        public Task<AgentRunResult> RunAsync(
            string prompt,
            AgentRuntimeContext runtimeContext)
        {
            return RunAsync(
                prompt,
                runtimeContext,
                CancellationToken.None);
        }


        public Task<AgentRunResult> RunAsync(
            string prompt,
            AgentRuntimeContext runtimeContext,
            CancellationToken cancellationToken)
        {
            if (runtimeContext == null)
            {
                throw new ArgumentNullException(
                    nameof(runtimeContext));
            }


            EnsureProviderConfigured();


            return _engine.RunAsync(
                prompt,
                runtimeContext.Capabilities,
                runtimeContext.CapabilityPolicy,
                runtimeContext.ProviderOptions,
                cancellationToken);
        }

        //--------------------------------------------------
        // Isolated Agent Run API
        //--------------------------------------------------

        public Task<AgentRunResult> RunIsolatedAsync(
            string prompt)
        {
            return RunIsolatedAsync(
                prompt,
                CancellationToken.None);
        }


        public Task<AgentRunResult> RunIsolatedAsync(
            string prompt,
            CancellationToken cancellationToken)
        {
            EnsureProviderConfigured();


            return _engine.RunIsolatedAsync(
                prompt,
                cancellationToken);
        }


        //--------------------------------------------------
        // Engine Construction
        //--------------------------------------------------

        private void RebuildConversationEngine()
        {
            IProvider primaryProvider =
                _providerChain.PrimaryProvider;


            if (primaryProvider == null)
            {
                _engine =
                    null;

                return;
            }


            _engine =
                new ConversationEngine(
                    _providerChain,
                    _providerRetryPolicy,
                    _providerHealthTracker,
                    _capabilityRegistry,
                    _capabilityDispatcher,
                    _agentObservers,
                    _providerFailureClassifier,
                    _providerToolBuilder);


            _engine.ProviderTimeout =
                _providerTimeout;


            _engine.RunTimeout =
                _runTimeout;


            _engine.MaxCapabilityRounds =
                _maxCapabilityRounds;


            _engine.SystemPrompt =
                _systemPrompt;
        }


        //--------------------------------------------------
        // Validation
        //--------------------------------------------------

        private void EnsureProviderConfigured()
        {
            if (
                _providerChain.HasPrimaryProvider &&
                _engine != null)
            {
                return;
            }


            throw new InvalidOperationException(
                "No provider configured. Call UseProvider() first.");
        }


        private void ThrowIfRunning(
            string message)
        {
            if (IsRunning)
            {
                throw new InvalidOperationException(
                    message);
            }
        }
    }
}
