using System;
using System.Collections.Generic;

namespace AIRuntime.Runtime.Services.Agent
{
    public sealed class AgentObserverCollection
    {
        private readonly object _gate =
            new object();

        private readonly List<IAgentObserver> _observers =
            new();


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

            lock (_gate)
            {
                _observers.Add(observer);
            }
        }


        public void Remove(
            IAgentObserver observer)
        {
            lock (_gate)
            {
                _observers.Remove(observer);
            }
        }


        public void Publish(
            AgentEvent agentEvent)
        {
            if (agentEvent == null)
            {
                throw new ArgumentNullException(
                    nameof(agentEvent));
            }

            IAgentObserver[] snapshot;

            lock (_gate)
            {
                snapshot =
                    _observers.ToArray();
            }

            foreach (IAgentObserver observer in snapshot)
            {
                try
                {
                    observer.OnAgentEvent(
                        agentEvent);
                }
                catch (Exception exception)
                {
                    // Observers are diagnostics and extension points. A broken
                    // UI, telemetry, or plugin observer must never change the
                    // outcome of the agent run it is watching.
                    try
                    {
                        Console.Error.WriteLine(
                            $"AIRuntime agent observer '{observer.GetType().FullName}' failed with {exception.GetType().FullName}. Event payloads are intentionally omitted.");
                    }
                    catch
                    {
                        // Even diagnostic reporting is outside the run
                        // contract and therefore best effort.
                    }
                }
            }
        }
    }
}
