using System;
using System.Collections.Generic;
using System.IO;
using Serilog;

namespace ZB.MOM.WW.LmxProxy.Host.Configuration
{
    /// <summary>
    ///     Validates the LmxProxy configuration at startup.
    ///     Throws InvalidOperationException on any validation error.
    /// </summary>
    public static class ConfigurationValidator
    {
        private static readonly ILogger Log = Serilog.Log.ForContext(typeof(ConfigurationValidator));

        /// <summary>
        ///     Validates all configuration settings and logs the effective values.
        ///     Throws on first validation error.
        /// </summary>
        public static void ValidateAndLog(LmxProxyConfiguration config)
        {
            var errors = new List<string>();

            // GrpcPort
            if (config.GrpcPort < 1 || config.GrpcPort > 65535)
                errors.Add($"GrpcPort must be 1-65535, got {config.GrpcPort}");

            // Connection
            var conn = config.Connection;
            if (conn.MonitorIntervalSeconds <= 0)
                errors.Add($"Connection.MonitorIntervalSeconds must be > 0, got {conn.MonitorIntervalSeconds}");
            if (conn.ConnectionTimeoutSeconds <= 0)
                errors.Add($"Connection.ConnectionTimeoutSeconds must be > 0, got {conn.ConnectionTimeoutSeconds}");
            if (conn.ReadTimeoutSeconds <= 0)
                errors.Add($"Connection.ReadTimeoutSeconds must be > 0, got {conn.ReadTimeoutSeconds}");
            if (conn.WriteTimeoutSeconds <= 0)
                errors.Add($"Connection.WriteTimeoutSeconds must be > 0, got {conn.WriteTimeoutSeconds}");
            if (conn.MaxConcurrentOperations <= 0)
                errors.Add($"Connection.MaxConcurrentOperations must be > 0, got {conn.MaxConcurrentOperations}");
            if (conn.NodeName != null && conn.NodeName.Length > 255)
                errors.Add("Connection.NodeName must be <= 255 characters");
            if (conn.GalaxyName != null && conn.GalaxyName.Length > 255)
                errors.Add("Connection.GalaxyName must be <= 255 characters");

            // Subscription
            var sub = config.Subscription;
            if (sub.ChannelCapacity < 0 || sub.ChannelCapacity > 100000)
                errors.Add($"Subscription.ChannelCapacity must be 0-100000, got {sub.ChannelCapacity}");
            var validModes = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
                { "DropOldest", "DropNewest", "Wait" };
            if (!validModes.Contains(sub.ChannelFullMode))
                errors.Add($"Subscription.ChannelFullMode must be DropOldest, DropNewest, or Wait, got '{sub.ChannelFullMode}'");

            // ServiceRecovery
            var sr = config.ServiceRecovery;
            if (sr.FirstFailureDelayMinutes < 0)
                errors.Add($"ServiceRecovery.FirstFailureDelayMinutes must be >= 0, got {sr.FirstFailureDelayMinutes}");
            if (sr.SecondFailureDelayMinutes < 0)
                errors.Add($"ServiceRecovery.SecondFailureDelayMinutes must be >= 0, got {sr.SecondFailureDelayMinutes}");
            if (sr.SubsequentFailureDelayMinutes < 0)
                errors.Add($"ServiceRecovery.SubsequentFailureDelayMinutes must be >= 0, got {sr.SubsequentFailureDelayMinutes}");
            if (sr.ResetPeriodDays <= 0)
                errors.Add($"ServiceRecovery.ResetPeriodDays must be > 0, got {sr.ResetPeriodDays}");

            // TLS
            if (config.Tls.Enabled)
            {
                if (!File.Exists(config.Tls.ServerCertificatePath))
                    Log.Warning("TLS enabled but server certificate not found at {Path} (will auto-generate)",
                        config.Tls.ServerCertificatePath);
                if (!File.Exists(config.Tls.ServerKeyPath))
                    Log.Warning("TLS enabled but server key not found at {Path} (will auto-generate)",
                        config.Tls.ServerKeyPath);
            }

            // WebServer
            if (config.WebServer.Enabled)
            {
                if (config.WebServer.Port < 1 || config.WebServer.Port > 65535)
                    errors.Add($"WebServer.Port must be 1-65535, got {config.WebServer.Port}");
            }

            if (errors.Count > 0)
            {
                foreach (var error in errors)
                    Log.Error("Configuration error: {Error}", error);
                throw new InvalidOperationException(
                    $"Configuration validation failed with {errors.Count} error(s): {string.Join("; ", errors)}");
            }

            // Log effective configuration
            Log.Information("Configuration validated successfully");
            Log.Information("  GrpcPort: {Port}", config.GrpcPort);
            Log.Information("  ApiKeyConfigFile: {File}", config.ApiKeyConfigFile);
            Log.Information("  Connection.AutoReconnect: {AutoReconnect}", conn.AutoReconnect);
            Log.Information("  Connection.MonitorIntervalSeconds: {Interval}", conn.MonitorIntervalSeconds);
            Log.Information("  Connection.MaxConcurrentOperations: {Max}", conn.MaxConcurrentOperations);
            Log.Information("  Subscription.ChannelCapacity: {Capacity}", sub.ChannelCapacity);
            Log.Information("  Subscription.ChannelFullMode: {Mode}", sub.ChannelFullMode);
            Log.Information("  Tls.Enabled: {Enabled}", config.Tls.Enabled);
            Log.Information("  WebServer.Enabled: {Enabled}, Port: {Port}", config.WebServer.Enabled, config.WebServer.Port);
        }
    }
}
