using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
using Serilog;
using ZB.MOM.WW.LmxProxy.Host.Domain;

namespace ZB.MOM.WW.LmxProxy.Host.Services
{
    /// <summary>
    ///     Service for collecting and formatting status information from various LmxProxy components
    /// </summary>
    public class StatusReportService
    {
        private static readonly ILogger Logger = Log.ForContext<StatusReportService>();
        private readonly DetailedHealthCheckService? _detailedHealthCheckService;
        private readonly HealthCheckService _healthCheckService;
        private readonly PerformanceMetrics _performanceMetrics;

        private readonly IScadaClient _scadaClient;
        private readonly SubscriptionManager _subscriptionManager;

        /// <summary>
        ///     Initializes a new instance of the StatusReportService class
        /// </summary>
        public StatusReportService(
            IScadaClient scadaClient,
            SubscriptionManager subscriptionManager,
            PerformanceMetrics performanceMetrics,
            HealthCheckService healthCheckService,
            DetailedHealthCheckService? detailedHealthCheckService = null)
        {
            _scadaClient = scadaClient ?? throw new ArgumentNullException(nameof(scadaClient));
            _subscriptionManager = subscriptionManager ?? throw new ArgumentNullException(nameof(subscriptionManager));
            _performanceMetrics = performanceMetrics ?? throw new ArgumentNullException(nameof(performanceMetrics));
            _healthCheckService = healthCheckService ?? throw new ArgumentNullException(nameof(healthCheckService));
            _detailedHealthCheckService = detailedHealthCheckService;
        }

        /// <summary>
        ///     Generates a comprehensive status report as HTML
        /// </summary>
        public async Task<string> GenerateHtmlReportAsync()
        {
            try
            {
                StatusData statusData = await CollectStatusDataAsync();
                return GenerateHtmlFromStatusData(statusData);
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error generating HTML status report");
                return GenerateErrorHtml(ex);
            }
        }

        /// <summary>
        ///     Generates a comprehensive status report as JSON
        /// </summary>
        public async Task<string> GenerateJsonReportAsync()
        {
            try
            {
                StatusData statusData = await CollectStatusDataAsync();
                return JsonSerializer.Serialize(statusData, new JsonSerializerOptions
                {
                    WriteIndented = true,
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error generating JSON status report");
                return JsonSerializer.Serialize(new { error = ex.Message }, new JsonSerializerOptions
                {
                    WriteIndented = true,
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
                });
            }
        }

        /// <summary>
        ///     Checks if the service is healthy
        /// </summary>
        public async Task<bool> IsHealthyAsync()
        {
            try
            {
                HealthCheckResult healthResult = await _healthCheckService.CheckHealthAsync(new HealthCheckContext());
                return healthResult.Status == HealthStatus.Healthy;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error checking health status");
                return false;
            }
        }

        /// <summary>
        ///     Collects status data from all components
        /// </summary>
        private async Task<StatusData> CollectStatusDataAsync()
        {
            var statusData = new StatusData
            {
                Timestamp = DateTime.UtcNow,
                ServiceName = "ZB.MOM.WW.LmxProxy.Host",
                Version = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "Unknown"
            };

            // Collect connection status
            statusData.Connection = new ConnectionStatus
            {
                IsConnected = _scadaClient.IsConnected,
                State = _scadaClient.ConnectionState.ToString(),
                NodeName = "N/A", // Could be extracted from configuration if needed
                GalaxyName = "N/A" // Could be extracted from configuration if needed
            };

            // Collect subscription statistics
            SubscriptionStats subscriptionStats = _subscriptionManager.GetSubscriptionStats();
            statusData.Subscriptions = new SubscriptionStatus
            {
                TotalClients = subscriptionStats.TotalClients,
                TotalTags = subscriptionStats.TotalTags,
                ActiveSubscriptions = subscriptionStats.TotalTags // Assuming same for simplicity
            };

            // Collect performance metrics
            Dictionary<string, MetricsStatistics> perfMetrics = _performanceMetrics.GetStatistics();
            statusData.Performance = new PerformanceStatus
            {
                TotalOperations = perfMetrics.Values.Sum(m => m.TotalCount),
                AverageSuccessRate = perfMetrics.Count > 0 ? perfMetrics.Values.Average(m => m.SuccessRate) : 1.0,
                Operations = perfMetrics.ToDictionary(
                    kvp => kvp.Key,
                    kvp => new OperationStatus
                    {
                        TotalCount = kvp.Value.TotalCount,
                        SuccessRate = kvp.Value.SuccessRate,
                        AverageMilliseconds = kvp.Value.AverageMilliseconds,
                        MinMilliseconds = kvp.Value.MinMilliseconds,
                        MaxMilliseconds = kvp.Value.MaxMilliseconds
                    })
            };

            // Collect health check results
            try
            {
                HealthCheckResult healthResult = await _healthCheckService.CheckHealthAsync(new HealthCheckContext());
                statusData.Health = new HealthInfo
                {
                    Status = healthResult.Status.ToString(),
                    Description = healthResult.Description ?? "",
                    Data = healthResult.Data?.ToDictionary(kvp => kvp.Key, kvp => kvp.Value?.ToString() ?? "") ??
                           new Dictionary<string, string>()
                };

                // Collect detailed health check if available
                if (_detailedHealthCheckService != null)
                {
                    HealthCheckResult detailedHealthResult =
                        await _detailedHealthCheckService.CheckHealthAsync(new HealthCheckContext());
                    statusData.DetailedHealth = new HealthInfo
                    {
                        Status = detailedHealthResult.Status.ToString(),
                        Description = detailedHealthResult.Description ?? "",
                        Data = detailedHealthResult.Data?.ToDictionary(kvp => kvp.Key,
                            kvp => kvp.Value?.ToString() ?? "") ?? new Dictionary<string, string>()
                    };
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error collecting health check data");
                statusData.Health = new HealthInfo
                {
                    Status = "Error",
                    Description = $"Health check failed: {ex.Message}",
                    Data = new Dictionary<string, string>()
                };
            }

            return statusData;
        }

        /// <summary>
        ///     Generates HTML from status data
        /// </summary>
        private static string GenerateHtmlFromStatusData(StatusData statusData)
        {
            var html = new StringBuilder();

            html.AppendLine("<!DOCTYPE html>");
            html.AppendLine("<html>");
            html.AppendLine("<head>");
            html.AppendLine("    <title>LmxProxy Status</title>");
            html.AppendLine("    <meta charset=\"utf-8\">");
            html.AppendLine("    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            html.AppendLine("    <meta http-equiv=\"refresh\" content=\"30\">");
            html.AppendLine("    <style>");
            html.AppendLine(
                "        body { font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }");
            html.AppendLine(
                "        .container { max-width: 1200px; margin: 0 auto; background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }");
            html.AppendLine("        .header { text-align: center; margin-bottom: 30px; }");
            html.AppendLine(
                "        .status-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }");
            html.AppendLine(
                "        .status-card { background: #f9f9f9; padding: 15px; border-radius: 6px; border-left: 4px solid #007acc; }");
            html.AppendLine("        .status-card h3 { margin-top: 0; color: #333; }");
            html.AppendLine("        .status-value { font-weight: bold; color: #007acc; }");
            html.AppendLine("        .status-healthy { color: #28a745; }");
            html.AppendLine("        .status-warning { color: #ffc107; }");
            html.AppendLine("        .status-error { color: #dc3545; }");
            html.AppendLine("        .status-connected { border-left-color: #28a745; }");
            html.AppendLine("        .status-disconnected { border-left-color: #dc3545; }");
            html.AppendLine("        table { width: 100%; border-collapse: collapse; margin-top: 10px; }");
            html.AppendLine("        th, td { text-align: left; padding: 8px; border-bottom: 1px solid #ddd; }");
            html.AppendLine("        th { background-color: #f2f2f2; }");
            html.AppendLine(
                "        .timestamp { text-align: center; margin-top: 20px; color: #666; font-size: 0.9em; }");
            html.AppendLine("    </style>");
            html.AppendLine("</head>");
            html.AppendLine("<body>");
            html.AppendLine("    <div class=\"container\">");

            // Header
            html.AppendLine("        <div class=\"header\">");
            html.AppendLine("            <h1>LmxProxy Status Dashboard</h1>");
            html.AppendLine($"            <p>Service: {statusData.ServiceName} | Version: {statusData.Version}</p>");
            html.AppendLine("        </div>");

            html.AppendLine("        <div class=\"status-grid\">");

            // Connection Status Card
            string connectionClass = statusData.Connection.IsConnected ? "status-connected" : "status-disconnected";
            string connectionStatusText = statusData.Connection.IsConnected ? "Connected" : "Disconnected";
            string connectionStatusClass = statusData.Connection.IsConnected ? "status-healthy" : "status-error";

            html.AppendLine($"            <div class=\"status-card {connectionClass}\">");
            html.AppendLine("                <h3>MxAccess Connection</h3>");
            html.AppendLine(
                $"                <p>Status: <span class=\"status-value {connectionStatusClass}\">{connectionStatusText}</span></p>");
            html.AppendLine(
                $"                <p>State: <span class=\"status-value\">{statusData.Connection.State}</span></p>");
            html.AppendLine("            </div>");

            // Subscription Status Card
            html.AppendLine("            <div class=\"status-card\">");
            html.AppendLine("                <h3>Subscriptions</h3>");
            html.AppendLine(
                $"                <p>Total Clients: <span class=\"status-value\">{statusData.Subscriptions.TotalClients}</span></p>");
            html.AppendLine(
                $"                <p>Total Tags: <span class=\"status-value\">{statusData.Subscriptions.TotalTags}</span></p>");
            html.AppendLine(
                $"                <p>Active Subscriptions: <span class=\"status-value\">{statusData.Subscriptions.ActiveSubscriptions}</span></p>");
            html.AppendLine("            </div>");

            // Performance Status Card
            html.AppendLine("            <div class=\"status-card\">");
            html.AppendLine("                <h3>Performance</h3>");
            html.AppendLine(
                $"                <p>Total Operations: <span class=\"status-value\">{statusData.Performance.TotalOperations:N0}</span></p>");
            html.AppendLine(
                $"                <p>Success Rate: <span class=\"status-value\">{statusData.Performance.AverageSuccessRate:P2}</span></p>");
            html.AppendLine("            </div>");

            // Health Status Card
            string healthStatusClass = statusData.Health.Status.ToLowerInvariant() switch
            {
                "healthy" => "status-healthy",
                "degraded" => "status-warning",
                _ => "status-error"
            };

            html.AppendLine("            <div class=\"status-card\">");
            html.AppendLine("                <h3>Health Status</h3>");
            html.AppendLine(
                $"                <p>Status: <span class=\"status-value {healthStatusClass}\">{statusData.Health.Status}</span></p>");
            html.AppendLine(
                $"                <p>Description: <span class=\"status-value\">{statusData.Health.Description}</span></p>");
            html.AppendLine("            </div>");

            html.AppendLine("        </div>");

            // Performance Metrics Table
            if (statusData.Performance.Operations.Any())
            {
                html.AppendLine("        <div class=\"status-card\" style=\"margin-top: 20px;\">");
                html.AppendLine("            <h3>Operation Performance Metrics</h3>");
                html.AppendLine("            <table>");
                html.AppendLine("                <tr>");
                html.AppendLine("                    <th>Operation</th>");
                html.AppendLine("                    <th>Count</th>");
                html.AppendLine("                    <th>Success Rate</th>");
                html.AppendLine("                    <th>Avg (ms)</th>");
                html.AppendLine("                    <th>Min (ms)</th>");
                html.AppendLine("                    <th>Max (ms)</th>");
                html.AppendLine("                </tr>");

                foreach (KeyValuePair<string, OperationStatus> operation in statusData.Performance.Operations)
                {
                    html.AppendLine("                <tr>");
                    html.AppendLine($"                    <td>{operation.Key}</td>");
                    html.AppendLine($"                    <td>{operation.Value.TotalCount:N0}</td>");
                    html.AppendLine($"                    <td>{operation.Value.SuccessRate:P2}</td>");
                    html.AppendLine($"                    <td>{operation.Value.AverageMilliseconds:F2}</td>");
                    html.AppendLine($"                    <td>{operation.Value.MinMilliseconds:F2}</td>");
                    html.AppendLine($"                    <td>{operation.Value.MaxMilliseconds:F2}</td>");
                    html.AppendLine("                </tr>");
                }

                html.AppendLine("            </table>");
                html.AppendLine("        </div>");
            }

            // Timestamp
            html.AppendLine(
                $"        <div class=\"timestamp\">Last updated: {statusData.Timestamp:yyyy-MM-dd HH:mm:ss} UTC</div>");

            html.AppendLine("    </div>");
            html.AppendLine("</body>");
            html.AppendLine("</html>");

            return html.ToString();
        }

        /// <summary>
        ///     Generates error HTML when status collection fails
        /// </summary>
        private static string GenerateErrorHtml(Exception ex)
        {
            return $@"<!DOCTYPE html>
<html>
<head>
    <title>LmxProxy Status - Error</title>
    <meta charset=""utf-8"">
    <style>
        body {{ font-family: Arial, sans-serif; margin: 40px; background-color: #f5f5f5; }}
        .container {{ max-width: 800px; margin: 0 auto; background-color: white; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        .error {{ color: #dc3545; background-color: #f8d7da; padding: 15px; border-radius: 6px; border: 1px solid #f5c6cb; }}
    </style>
</head>
<body>
    <div class=""container"">
        <h1>LmxProxy Status Dashboard</h1>
        <div class=""error"">
            <h3>Error Loading Status</h3>
            <p>An error occurred while collecting status information:</p>
            <p><strong>{ex.Message}</strong></p>
        </div>
        <div style=""text-align: center; margin-top: 20px; color: #666; font-size: 0.9em;"">
            Last updated: {DateTime.UtcNow:yyyy-MM-dd HH:mm:ss} UTC
        </div>
    </div>
</body>
</html>";
        }
    }

    /// <summary>
    ///     Data structure for holding complete status information
    /// </summary>
    public class StatusData
    {
        public DateTime Timestamp { get; set; }
        public string ServiceName { get; set; } = "";
        public string Version { get; set; } = "";
        public ConnectionStatus Connection { get; set; } = new();
        public SubscriptionStatus Subscriptions { get; set; } = new();
        public PerformanceStatus Performance { get; set; } = new();
        public HealthInfo Health { get; set; } = new();
        public HealthInfo? DetailedHealth { get; set; }
    }

    /// <summary>
    ///     Connection status information
    /// </summary>
    public class ConnectionStatus
    {
        public bool IsConnected { get; set; }
        public string State { get; set; } = "";
        public string NodeName { get; set; } = "";
        public string GalaxyName { get; set; } = "";
    }

    /// <summary>
    ///     Subscription status information
    /// </summary>
    public class SubscriptionStatus
    {
        public int TotalClients { get; set; }
        public int TotalTags { get; set; }
        public int ActiveSubscriptions { get; set; }
    }

    /// <summary>
    ///     Performance status information
    /// </summary>
    public class PerformanceStatus
    {
        public long TotalOperations { get; set; }
        public double AverageSuccessRate { get; set; }
        public Dictionary<string, OperationStatus> Operations { get; set; } = new();
    }

    /// <summary>
    ///     Individual operation status
    /// </summary>
    public class OperationStatus
    {
        public long TotalCount { get; set; }
        public double SuccessRate { get; set; }
        public double AverageMilliseconds { get; set; }
        public double MinMilliseconds { get; set; }
        public double MaxMilliseconds { get; set; }
    }

    /// <summary>
    ///     Health check status information
    /// </summary>
    public class HealthInfo
    {
        public string Status { get; set; } = "";
        public string Description { get; set; } = "";
        public Dictionary<string, string> Data { get; set; } = new();
    }
}
