using System;
using System.Collections.Generic;
using System.Linq;

namespace EonaCat.LogStack.Telemetry
{
    /// <summary>
    /// Monitors the health status of the logger and flows.
    /// Tracks degradation, failures, and recovery events.
    /// </summary>
    public sealed class HealthMonitor
    {
        private Dictionary<string, ComponentHealth> _componentHealth = new();
        private OverallHealth _overallHealth = new();
        private readonly object _lock = new();

        /// <summary>
        /// Gets overall health status
        /// </summary>
        public HealthStatus OverallStatus
        {
            get
            {
                lock (_lock)
                {
                    return _overallHealth.Status;
                }
            }
        }

        /// <summary>
        /// Gets health status of a component
        /// </summary>
        public ComponentHealth? GetComponentHealth(string name)
        {
            lock (_lock)
            {
                return _componentHealth.TryGetValue(name, out var health) ? health : null;
            }
        }

        /// <summary>
        /// Updates health of a component
        /// </summary>
        public void UpdateComponentHealth(string name, HealthStatus status, string? message = null)
        {
            lock (_lock)
            {
                var now = DateTime.UtcNow;

                if (!_componentHealth.TryGetValue(name, out var health))
                {
                    health = new ComponentHealth { Name = name };
                    _componentHealth[name] = health;
                }

                var previousStatus = health.Status;
                health.Status = status;
                health.Message = message;
                health.LastUpdated = now;

                if (status != previousStatus)
                {
                    health.StatusChangedAt = now;
                    health.StatusChangeCount++;
                }

                RecalculateOverallHealth();
            }
        }

        /// <summary>
        /// Records an error event
        /// </summary>
        public void RecordError(string componentName, Exception exception)
        {
            lock (_lock)
            {
                if (!_componentHealth.TryGetValue(componentName, out var health))
                {
                    health = new ComponentHealth { Name = componentName };
                    _componentHealth[componentName] = health;
                }

                health.ErrorCount++;
                health.LastErrorAt = DateTime.UtcNow;
                health.LastError = exception;

                if (health.ErrorCount > 10)
                {
                    health.Status = HealthStatus.Degraded;
                }
                if (health.ErrorCount > 50)
                {
                    health.Status = HealthStatus.Unhealthy;
                }

                RecalculateOverallHealth();
            }
        }

        /// <summary>
        /// Recovers a component
        /// </summary>
        public void RecoverComponent(string componentName)
        {
            lock (_lock)
            {
                if (_componentHealth.TryGetValue(componentName, out var health))
                {
                    health.Status = HealthStatus.Healthy;
                    health.ErrorCount = 0;
                    health.Message = null;
                    RecalculateOverallHealth();
                }
            }
        }

        /// <summary>
        /// Gets all component health statuses
        /// </summary>
        public IReadOnlyDictionary<string, ComponentHealth> GetAllComponentHealth()
        {
            lock (_lock)
            {
                return new Dictionary<string, ComponentHealth>(_componentHealth);
            }
        }

        /// <summary>
        /// Gets health snapshot
        /// </summary>
        public HealthSnapshot GetSnapshot()
        {
            lock (_lock)
            {
                return new HealthSnapshot
                {
                    OverallStatus = _overallHealth.Status,
                    OverallMessage = _overallHealth.Message,
                    CapturedAt = DateTime.UtcNow,
                    Components = new Dictionary<string, ComponentHealth>(_componentHealth),
                    TotalComponents = _componentHealth.Count,
                    HealthyComponents = _componentHealth.Count(kvp => kvp.Value.Status == HealthStatus.Healthy),
                    DegradedComponents = _componentHealth.Count(kvp => kvp.Value.Status == HealthStatus.Degraded),
                    UnhealthyComponents = _componentHealth.Count(kvp => kvp.Value.Status == HealthStatus.Unhealthy)
                };
            }
        }

        private void RecalculateOverallHealth()
        {
            if (_componentHealth.Count == 0)
            {
                _overallHealth.Status = HealthStatus.Unknown;
                return;
            }

            // If any component is unhealthy, overall is unhealthy
            if (_componentHealth.Values.Any(h => h.Status == HealthStatus.Unhealthy))
            {
                _overallHealth.Status = HealthStatus.Unhealthy;
                _overallHealth.Message = "One or more components are unhealthy";
            }
            // If any component is degraded, overall is degraded
            else if (_componentHealth.Values.Any(h => h.Status == HealthStatus.Degraded))
            {
                _overallHealth.Status = HealthStatus.Degraded;
                _overallHealth.Message = "One or more components are degraded";
            }
            // If all are healthy, overall is healthy
            else if (_componentHealth.Values.All(h => h.Status == HealthStatus.Healthy))
            {
                _overallHealth.Status = HealthStatus.Healthy;
                _overallHealth.Message = "All components are healthy";
            }
            else
            {
                _overallHealth.Status = HealthStatus.Unknown;
            }
        }
    }

    /// <summary>
    /// Health status enumeration
    /// </summary>
    public enum HealthStatus
    {
        Unknown = 0,
        Healthy = 1,
        Degraded = 2,
        Unhealthy = 3
    }

    /// <summary>
    /// Health status of a single component
    /// </summary>
    public sealed class ComponentHealth
    {
        public string Name { get; set; }
        public HealthStatus Status { get; set; } = HealthStatus.Unknown;
        public string? Message { get; set; }
        public DateTime LastUpdated { get; set; } = DateTime.UtcNow;
        public DateTime? StatusChangedAt { get; set; }
        public int StatusChangeCount { get; set; }
        public long ErrorCount { get; set; }
        public DateTime? LastErrorAt { get; set; }
        public Exception? LastError { get; set; }
    }

    /// <summary>
    /// Overall health information
    /// </summary>
    public sealed class OverallHealth
    {
        public HealthStatus Status { get; set; } = HealthStatus.Unknown;
        public string? Message { get; set; }
    }

    /// <summary>
    /// Snapshot of health status
    /// </summary>
    public sealed class HealthSnapshot
    {
        public HealthStatus OverallStatus { get; set; }
        public string? OverallMessage { get; set; }
        public DateTime CapturedAt { get; set; }
        public Dictionary<string, ComponentHealth> Components { get; set; } = new();
        public int TotalComponents { get; set; }
        public int HealthyComponents { get; set; }
        public int DegradedComponents { get; set; }
        public int UnhealthyComponents { get; set; }

        public override string ToString()
        {
            return $"{OverallStatus} | Total: {TotalComponents} | Healthy: {HealthyComponents} | Degraded: {DegradedComponents} | Unhealthy: {UnhealthyComponents}";
        }
    }
}
