using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Serilog;
using ZB.MOM.WW.LmxProxy.Host.Domain;
using HealthCheckService = ZB.MOM.WW.LmxProxy.Host.Health.HealthCheckService;
using ZB.MOM.WW.LmxProxy.Host.Metrics;
using ZB.MOM.WW.LmxProxy.Host.Subscriptions;

namespace ZB.MOM.WW.LmxProxy.Host.Status
{
    /// <summary>
    ///     Aggregates health, metrics, and subscription data into status reports.
    /// </summary>
    public class StatusReportService
    {
        private static readonly ILogger Logger = Log.ForContext<StatusReportService>();

        private readonly IScadaClient _scadaClient;
        private readonly SubscriptionManager _subscriptionManager;
        private readonly PerformanceMetrics _performanceMetrics;
        private readonly HealthCheckService _healthCheckService;

        public StatusReportService(
            IScadaClient scadaClient,
            SubscriptionManager subscriptionManager,
            PerformanceMetrics performanceMetrics,
            HealthCheckService healthCheckService)
        {
            _scadaClient = scadaClient;
            _subscriptionManager = subscriptionManager;
            _performanceMetrics = performanceMetrics;
            _healthCheckService = healthCheckService;
        }

        public async Task<string> GenerateHtmlReportAsync()
        {
            try
            {
                var statusData = await CollectStatusDataAsync();
                return GenerateHtmlFromStatusData(statusData);
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Failed to generate HTML report");
                return GenerateErrorHtml(ex);
            }
        }

        public async Task<string> GenerateJsonReportAsync()
        {
            var statusData = await CollectStatusDataAsync();
            var settings = new JsonSerializerSettings
            {
                Formatting = Formatting.Indented,
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            };
            return JsonConvert.SerializeObject(statusData, settings);
        }

        public async Task<bool> IsHealthyAsync()
        {
            var result = await _healthCheckService.CheckHealthAsync(new HealthCheckContext());
            return result.Status == HealthStatus.Healthy;
        }

        private async Task<StatusData> CollectStatusDataAsync()
        {
            var statusData = new StatusData
            {
                Timestamp = DateTime.UtcNow,
                ServiceName = "ZB.MOM.WW.LmxProxy.Host",
                Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0.0"
            };

            // Connection info
            statusData.Connection = new ConnectionStatus
            {
                IsConnected = _scadaClient.IsConnected,
                State = _scadaClient.ConnectionState.ToString(),
                ConnectedSince = _scadaClient.IsConnected ? _scadaClient.ConnectedSince : (DateTime?)null,
                ReconnectCount = _scadaClient.ReconnectCount
            };

            // Subscription stats
            var subStats = _subscriptionManager.GetStats();
            statusData.Subscriptions = new SubscriptionStatus
            {
                TotalClients = subStats.TotalClients,
                TotalTags = subStats.TotalTags,
                ActiveSubscriptions = subStats.ActiveSubscriptions,
                TotalDelivered = subStats.TotalDelivered,
                TotalDropped = subStats.TotalDropped
            };

            // Performance stats
            var allStats = _performanceMetrics.GetStatistics();
            long totalOps = 0;
            double totalSuccessRate = 0;
            int opCount = 0;

            foreach (var kvp in allStats)
            {
                totalOps += kvp.Value.TotalCount;
                totalSuccessRate += kvp.Value.SuccessRate;
                opCount++;

                statusData.Performance.Operations[kvp.Key] = new OperationStatus
                {
                    TotalCount = kvp.Value.TotalCount,
                    SuccessRate = kvp.Value.SuccessRate,
                    AverageMilliseconds = kvp.Value.AverageMilliseconds,
                    MinMilliseconds = kvp.Value.MinMilliseconds,
                    MaxMilliseconds = kvp.Value.MaxMilliseconds,
                    Percentile95Milliseconds = kvp.Value.Percentile95Milliseconds
                };
            }

            statusData.Performance.TotalOperations = totalOps;
            statusData.Performance.AverageSuccessRate = opCount > 0
                ? totalSuccessRate / opCount
                : 1.0;

            // Health check
            var healthResult = await _healthCheckService.CheckHealthAsync(new HealthCheckContext());
            statusData.Health = new HealthInfo
            {
                Status = healthResult.Status.ToString(),
                Description = healthResult.Description ?? ""
            };
            if (healthResult.Data != null)
            {
                foreach (var kvp in healthResult.Data)
                {
                    statusData.Health.Data[kvp.Key] = kvp.Value?.ToString() ?? "";
                }
            }

            return statusData;
        }

        private static string GenerateHtmlFromStatusData(StatusData statusData)
        {
            var sb = new StringBuilder();
            sb.AppendLine("<!DOCTYPE html>");
            sb.AppendLine("<html lang=\"en\">");
            sb.AppendLine("<head>");
            sb.AppendLine("  <meta charset=\"utf-8\">");
            sb.AppendLine("  <meta http-equiv=\"refresh\" content=\"30\">");
            sb.AppendLine("  <title>LmxProxy Status</title>");
            sb.AppendLine("  <style>");
            sb.AppendLine("    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; margin: 20px; background: #f5f5f5; }");
            sb.AppendLine("    h1 { color: #333; }");
            sb.AppendLine("    .card { background: white; border-radius: 4px; padding: 16px; margin-bottom: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); }");
            sb.AppendLine("    .card-green { border-left: 4px solid #28a745; }");
            sb.AppendLine("    .card-yellow { border-left: 4px solid #ffc107; }");
            sb.AppendLine("    .card-red { border-left: 4px solid #dc3545; }");
            sb.AppendLine("    .grid { display: flex; flex-wrap: wrap; gap: 16px; }");
            sb.AppendLine("    .grid-item { flex: 1; min-width: 300px; }");
            sb.AppendLine("    table { width: 100%; border-collapse: collapse; }");
            sb.AppendLine("    th, td { text-align: left; padding: 8px; border-bottom: 1px solid #eee; }");
            sb.AppendLine("    th { background: #f8f9fa; font-weight: 600; }");
            sb.AppendLine("    .status-healthy { color: #28a745; font-weight: bold; }");
            sb.AppendLine("    .status-degraded { color: #ffc107; font-weight: bold; }");
            sb.AppendLine("    .status-unhealthy { color: #dc3545; font-weight: bold; }");
            sb.AppendLine("    .footer { color: #999; font-size: 0.85em; margin-top: 20px; }");
            sb.AppendLine("  </style>");
            sb.AppendLine("</head>");
            sb.AppendLine("<body>");
            sb.AppendLine("  <h1>LmxProxy Status Dashboard</h1>");

            // Connection card
            var connClass = statusData.Connection.IsConnected ? "card-green" : "card-red";
            sb.AppendLine($"  <div class=\"grid\">");
            sb.AppendLine($"    <div class=\"grid-item\"><div class=\"card {connClass}\">");
            sb.AppendLine("      <h3>Connection</h3>");
            sb.AppendLine($"      <p><strong>Connected:</strong> {statusData.Connection.IsConnected}</p>");
            sb.AppendLine($"      <p><strong>State:</strong> {statusData.Connection.State}</p>");
            if (statusData.Connection.ConnectedSince.HasValue)
                sb.AppendLine($"      <p><strong>Connected Since:</strong> {statusData.Connection.ConnectedSince.Value:yyyy-MM-dd HH:mm:ss} UTC</p>");
            if (statusData.Connection.ReconnectCount > 0)
                sb.AppendLine($"      <p><strong>Reconnects:</strong> {statusData.Connection.ReconnectCount}</p>");
            if (!string.IsNullOrEmpty(statusData.Connection.NodeName))
                sb.AppendLine($"      <p><strong>Node:</strong> {statusData.Connection.NodeName}</p>");
            if (!string.IsNullOrEmpty(statusData.Connection.GalaxyName))
                sb.AppendLine($"      <p><strong>Galaxy:</strong> {statusData.Connection.GalaxyName}</p>");
            sb.AppendLine("    </div></div>");

            // Health card
            var healthClass = GetHealthCardClass(statusData.Health.Status);
            var healthCss = GetHealthStatusCss(statusData.Health.Status);
            sb.AppendLine($"    <div class=\"grid-item\"><div class=\"card {healthClass}\">");
            sb.AppendLine("      <h3>Health</h3>");
            sb.AppendLine($"      <p class=\"{healthCss}\">{statusData.Health.Status}</p>");
            sb.AppendLine($"      <p>{statusData.Health.Description}</p>");
            sb.AppendLine("    </div></div>");

            // Subscriptions card
            var subCardCss = statusData.Subscriptions.TotalDropped > 0 ? "card-yellow" : "card-green";
            sb.AppendLine($"    <div class=\"grid-item\"><div class=\"card {subCardCss}\">");
            sb.AppendLine("      <h3>Subscriptions</h3>");
            sb.AppendLine($"      <p><strong>Clients:</strong> {statusData.Subscriptions.TotalClients}</p>");
            sb.AppendLine($"      <p><strong>Tags:</strong> {statusData.Subscriptions.TotalTags}</p>");
            sb.AppendLine($"      <p><strong>Active:</strong> {statusData.Subscriptions.ActiveSubscriptions}</p>");
            sb.AppendLine($"      <p><strong>Delivered:</strong> {statusData.Subscriptions.TotalDelivered:N0}</p>");
            if (statusData.Subscriptions.TotalDropped > 0)
            {
                sb.AppendLine($"      <p style=\"color:red\"><strong>Dropped:</strong> {statusData.Subscriptions.TotalDropped:N0}</p>");
            }
            sb.AppendLine("    </div></div>");
            sb.AppendLine("  </div>");

            // RPC Operations table (always shown)
            sb.AppendLine("  <div class=\"card\">");
            sb.AppendLine("    <h3>RPC Operations</h3>");
            sb.AppendLine("    <table>");
            sb.AppendLine("      <tr><th>Operation</th><th>Count</th><th>Success Rate</th><th>Avg (ms)</th><th>Min (ms)</th><th>Max (ms)</th><th>P95 (ms)</th></tr>");

            // All known RPC operations — show each even if 0 calls
            var rpcNames = new[] { "Read", "ReadBatch", "Write", "WriteBatch", "Subscribe" };
            foreach (var rpcName in rpcNames)
            {
                var key = rpcName.Substring(0, 1).ToLowerInvariant() + rpcName.Substring(1);
                if (statusData.Performance.Operations.TryGetValue(key, out var op))
                {
                    sb.AppendLine($"      <tr>" +
                        $"<td>{rpcName}</td>" +
                        $"<td>{op.TotalCount}</td>" +
                        $"<td>{op.SuccessRate:P1}</td>" +
                        $"<td>{op.AverageMilliseconds:F1}</td>" +
                        $"<td>{op.MinMilliseconds:F1}</td>" +
                        $"<td>{op.MaxMilliseconds:F1}</td>" +
                        $"<td>{op.Percentile95Milliseconds:F1}</td>" +
                        $"</tr>");
                }
                else
                {
                    sb.AppendLine($"      <tr><td>{rpcName}</td><td>0</td><td>—</td><td>—</td><td>—</td><td>—</td><td>—</td></tr>");
                }
            }

            sb.AppendLine("    </table>");
            sb.AppendLine("  </div>");

            sb.AppendLine($"  <div class=\"footer\">Last updated: {statusData.Timestamp:yyyy-MM-dd HH:mm:ss} UTC | Service: {statusData.ServiceName} v{statusData.Version}</div>");
            sb.AppendLine("</body>");
            sb.AppendLine("</html>");
            return sb.ToString();
        }

        private static string GetHealthCardClass(string status)
        {
            switch (status)
            {
                case "Healthy": return "card-green";
                case "Degraded": return "card-yellow";
                default: return "card-red";
            }
        }

        private static string GetHealthStatusCss(string status)
        {
            switch (status)
            {
                case "Healthy": return "status-healthy";
                case "Degraded": return "status-degraded";
                default: return "status-unhealthy";
            }
        }

        private static string GenerateErrorHtml(Exception ex)
        {
            var sb = new StringBuilder();
            sb.AppendLine("<!DOCTYPE html>");
            sb.AppendLine("<html><head><title>LmxProxy Status - Error</title></head>");
            sb.AppendLine("<body>");
            sb.AppendLine("<h1>Error generating status report</h1>");
            sb.AppendLine($"<p>{ex.Message}</p>");
            sb.AppendLine("</body></html>");
            return sb.ToString();
        }
    }
}
