using System;
using System.IO;
using Microsoft.Extensions.Logging;

namespace ZB.MOM.WW.LmxProxy.Client
{
    /// <summary>
    /// Builder for creating configured instances of LmxProxyClient
    /// </summary>
    public class LmxProxyClientBuilder
    {
        private string? _host;
        private int _port = 5050;
        private string? _apiKey;
        private ILogger<LmxProxyClient>? _logger;
        private TimeSpan _defaultTimeout = TimeSpan.FromSeconds(30);
        private int _maxRetryAttempts = 3;
        private TimeSpan _retryDelay = TimeSpan.FromSeconds(1);
        private bool _enableMetrics;
        private string? _correlationIdHeader;
        private ClientTlsConfiguration? _tlsConfiguration;

        /// <summary>
        /// Sets the host address for the LmxProxy service
        /// </summary>
        /// <param name="host">The host address</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithHost(string host)
        {
            if (string.IsNullOrWhiteSpace(host))
                throw new ArgumentException("Host cannot be null or empty", nameof(host));

            _host = host;
            return this;
        }

        /// <summary>
        /// Sets the port for the LmxProxy service
        /// </summary>
        /// <param name="port">The port number</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithPort(int port)
        {
            if (port < 1 || port > 65535)
                throw new ArgumentOutOfRangeException(nameof(port), "Port must be between 1 and 65535");

            _port = port;
            return this;
        }

        /// <summary>
        /// Sets the API key for authentication
        /// </summary>
        /// <param name="apiKey">The API key</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithApiKey(string apiKey)
        {
            _apiKey = apiKey;
            return this;
        }

        /// <summary>
        /// Sets the logger instance
        /// </summary>
        /// <param name="logger">The logger</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithLogger(ILogger<LmxProxyClient> logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
            return this;
        }

        /// <summary>
        /// Sets the default timeout for operations
        /// </summary>
        /// <param name="timeout">The timeout duration</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithTimeout(TimeSpan timeout)
        {
            if (timeout <= TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(timeout), "Timeout must be positive");
            if (timeout > TimeSpan.FromMinutes(10))
                throw new ArgumentOutOfRangeException(nameof(timeout), "Timeout cannot exceed 10 minutes");

            _defaultTimeout = timeout;
            return this;
        }

        /// <summary>
        /// Enables SSL/TLS with the specified certificate
        /// </summary>
        /// <param name="certificatePath">Path to the certificate file</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithSslCredentials(string? certificatePath = null)
        {
            _tlsConfiguration ??= new ClientTlsConfiguration();
            _tlsConfiguration.UseTls = true;
            _tlsConfiguration.ServerCaCertificatePath = string.IsNullOrWhiteSpace(certificatePath) ? null : certificatePath;
            return this;
        }

        /// <summary>
        /// Applies a full TLS configuration to the client.
        /// </summary>
        /// <param name="configuration">The TLS configuration to apply.</param>
        /// <returns>The builder instance for method chaining.</returns>
        public LmxProxyClientBuilder WithTlsConfiguration(ClientTlsConfiguration configuration)
        {
            _tlsConfiguration = configuration ?? throw new ArgumentNullException(nameof(configuration));
            return this;
        }

        /// <summary>
        /// Sets the retry configuration
        /// </summary>
        /// <param name="maxAttempts">Maximum number of retry attempts</param>
        /// <param name="retryDelay">Delay between retries</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithRetryPolicy(int maxAttempts, TimeSpan retryDelay)
        {
            if (maxAttempts <= 0)
                throw new ArgumentOutOfRangeException(nameof(maxAttempts), "Max attempts must be positive");
            if (retryDelay <= TimeSpan.Zero)
                throw new ArgumentOutOfRangeException(nameof(retryDelay), "Retry delay must be positive");

            _maxRetryAttempts = maxAttempts;
            _retryDelay = retryDelay;
            return this;
        }

        /// <summary>
        /// Enables metrics collection
        /// </summary>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithMetrics()
        {
            _enableMetrics = true;
            return this;
        }

        /// <summary>
        /// Sets the correlation ID header name for request tracing
        /// </summary>
        /// <param name="headerName">The header name for correlation ID</param>
        /// <returns>The builder instance for method chaining</returns>
        public LmxProxyClientBuilder WithCorrelationIdHeader(string headerName)
        {
            if (string.IsNullOrEmpty(headerName))
                throw new ArgumentException("Header name cannot be null or empty", nameof(headerName));

            _correlationIdHeader = headerName;
            return this;
        }

        /// <summary>
        /// Builds the configured LmxProxyClient instance
        /// </summary>
        /// <returns>A configured LmxProxyClient instance</returns>
        public LmxProxyClient Build()
        {
            if (string.IsNullOrWhiteSpace(_host))
                throw new InvalidOperationException("Host must be specified");

            ValidateTlsConfiguration();

            var client = new LmxProxyClient(_host, _port, _apiKey, _tlsConfiguration, _logger)
            {
                DefaultTimeout = _defaultTimeout
            };

            // Store additional configuration for future use
            client.SetBuilderConfiguration(new ClientConfiguration
            {
                MaxRetryAttempts = _maxRetryAttempts,
                RetryDelay = _retryDelay,
                EnableMetrics = _enableMetrics,
                CorrelationIdHeader = _correlationIdHeader
            });

            return client;
        }

        private void ValidateTlsConfiguration()
        {
            if (_tlsConfiguration?.UseTls != true)
            {
                return;
            }

            if (!string.IsNullOrWhiteSpace(_tlsConfiguration.ServerCaCertificatePath) &&
                !File.Exists(_tlsConfiguration.ServerCaCertificatePath))
            {
                throw new FileNotFoundException(
                    $"Certificate file not found: {_tlsConfiguration.ServerCaCertificatePath}",
                    _tlsConfiguration.ServerCaCertificatePath);
            }

            if (!string.IsNullOrWhiteSpace(_tlsConfiguration.ClientCertificatePath) &&
                !File.Exists(_tlsConfiguration.ClientCertificatePath))
            {
                throw new FileNotFoundException(
                    $"Client certificate file not found: {_tlsConfiguration.ClientCertificatePath}",
                    _tlsConfiguration.ClientCertificatePath);
            }

            if (!string.IsNullOrWhiteSpace(_tlsConfiguration.ClientKeyPath) &&
                !File.Exists(_tlsConfiguration.ClientKeyPath))
            {
                throw new FileNotFoundException(
                    $"Client key file not found: {_tlsConfiguration.ClientKeyPath}",
                    _tlsConfiguration.ClientKeyPath);
            }
        }
    }

    /// <summary>
    /// Internal configuration class for storing builder settings
    /// </summary>
    internal class ClientConfiguration
    {
        /// <summary>
        /// Gets or sets the maximum number of retry attempts.
        /// </summary>
        public int MaxRetryAttempts { get; set; }

        /// <summary>
        /// Gets or sets the retry delay.
        /// </summary>
        public TimeSpan RetryDelay { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether metrics are enabled.
        /// </summary>
        public bool EnableMetrics { get; set; }

        /// <summary>
        /// Gets or sets the correlation ID header name.
        /// </summary>
        public string? CorrelationIdHeader { get; set; }
    }
}
