using System;
using System.Collections.Generic;

namespace StellaOps.Scanner.WebService.Options;

/// <summary>
/// Strongly typed configuration for the Scanner WebService host.
/// </summary>
public sealed class ScannerWebServiceOptions
{
    public const string SectionName = "scanner";

    /// <summary>
    /// Schema version for configuration consumers to coordinate breaking changes.
    /// </summary>
    public int SchemaVersion { get; set; } = 1;

    /// <summary>
    /// Mongo storage configuration used for catalog and job state.
    /// </summary>
    public StorageOptions Storage { get; set; } = new();

    /// <summary>
    /// Queue configuration used to enqueue scan jobs.
    /// </summary>
    public QueueOptions Queue { get; set; } = new();

    /// <summary>
    /// Object store configuration for SBOM artefacts.
    /// </summary>
    public ArtifactStoreOptions ArtifactStore { get; set; } = new();

    /// <summary>
    /// Feature flags toggling optional behaviours.
    /// </summary>
    public FeatureFlagOptions Features { get; set; } = new();

    /// <summary>
    /// Plug-in loader configuration.
    /// </summary>
    public PluginOptions Plugins { get; set; } = new();

    /// <summary>
    /// Telemetry configuration for logs, metrics, traces.
    /// </summary>
    public TelemetryOptions Telemetry { get; set; } = new();

    /// <summary>
    /// Authority / authentication configuration.
    /// </summary>
    public AuthorityOptions Authority { get; set; } = new();

    /// <summary>
    /// Signing configuration for report envelopes and attestations.
    /// </summary>
    public SigningOptions Signing { get; set; } = new();

    /// <summary>
    /// API-specific settings such as base path.
    /// </summary>
    public ApiOptions Api { get; set; } = new();

    public sealed class StorageOptions
    {
        public string Driver { get; set; } = "mongo";

        public string Dsn { get; set; } = string.Empty;

        public string? Database { get; set; }

        public int CommandTimeoutSeconds { get; set; } = 30;

        public int HealthCheckTimeoutSeconds { get; set; } = 5;

        public IList<string> Migrations { get; set; } = new List<string>();
    }

    public sealed class QueueOptions
    {
        public string Driver { get; set; } = "redis";

        public string Dsn { get; set; } = string.Empty;

        public string Namespace { get; set; } = "scanner";

        public int VisibilityTimeoutSeconds { get; set; } = 300;

        public int LeaseHeartbeatSeconds { get; set; } = 30;

        public int MaxDeliveryAttempts { get; set; } = 5;

        public IDictionary<string, string> DriverSettings { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }

    public sealed class ArtifactStoreOptions
    {
        public string Driver { get; set; } = "minio";

        public string Endpoint { get; set; } = string.Empty;

        public bool UseTls { get; set; } = true;

        public string AccessKey { get; set; } = string.Empty;

        public string SecretKey { get; set; } = string.Empty;

        public string? SecretKeyFile { get; set; }

        public string Bucket { get; set; } = "scanner-artifacts";

        public string? Region { get; set; }

        public bool EnableObjectLock { get; set; } = true;

        public int ObjectLockRetentionDays { get; set; } = 30;

        public IDictionary<string, string> Headers { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }

    public sealed class FeatureFlagOptions
    {
        public bool AllowAnonymousScanSubmission { get; set; }

        public bool EnableSignedReports { get; set; } = true;

        public bool EnablePolicyPreview { get; set; } = true;

        public IDictionary<string, bool> Experimental { get; set; } = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
    }

    public sealed class PluginOptions
    {
        public string? BaseDirectory { get; set; }

        public string? Directory { get; set; }

        public IList<string> SearchPatterns { get; set; } = new List<string>();

        public IList<string> OrderedPlugins { get; set; } = new List<string>();
    }

    public sealed class TelemetryOptions
    {
        public bool Enabled { get; set; } = true;

        public bool EnableTracing { get; set; } = true;

        public bool EnableMetrics { get; set; } = true;

        public bool EnableLogging { get; set; } = true;

        public bool EnableRequestLogging { get; set; } = true;

        public string MinimumLogLevel { get; set; } = "Information";

        public string? ServiceName { get; set; }

        public string? OtlpEndpoint { get; set; }

        public IDictionary<string, string> OtlpHeaders { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        public IDictionary<string, string> ResourceAttributes { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
    }

    public sealed class AuthorityOptions
    {
        public bool Enabled { get; set; }

        public bool AllowAnonymousFallback { get; set; } = true;

        public string Issuer { get; set; } = string.Empty;

        public string? MetadataAddress { get; set; }

        public bool RequireHttpsMetadata { get; set; } = true;

        public int BackchannelTimeoutSeconds { get; set; } = 30;

        public int TokenClockSkewSeconds { get; set; } = 60;

        public IList<string> Audiences { get; set; } = new List<string>();

        public IList<string> RequiredScopes { get; set; } = new List<string>();

        public IList<string> BypassNetworks { get; set; } = new List<string>();

        public string? ClientId { get; set; }

        public string? ClientSecret { get; set; }

        public string? ClientSecretFile { get; set; }

        public IList<string> ClientScopes { get; set; } = new List<string>();

        public ResilienceOptions Resilience { get; set; } = new();

        public sealed class ResilienceOptions
        {
            public bool? EnableRetries { get; set; }

            public IList<TimeSpan> RetryDelays { get; set; } = new List<TimeSpan>();

            public bool? AllowOfflineCacheFallback { get; set; }

            public TimeSpan? OfflineCacheTolerance { get; set; }
        }
    }

    public sealed class SigningOptions
    {
        public bool Enabled { get; set; } = false;

        public string KeyId { get; set; } = string.Empty;

        public string Algorithm { get; set; } = "ed25519";

        public string? KeyPem { get; set; }

        public string? KeyPemFile { get; set; }

        public string? CertificatePem { get; set; }

        public string? CertificatePemFile { get; set; }

        public string? CertificateChainPem { get; set; }

        public string? CertificateChainPemFile { get; set; }

        public int EnvelopeTtlSeconds { get; set; } = 600;
    }

    public sealed class ApiOptions
    {
        public string BasePath { get; set; } = "/api/v1";

        public string ScansSegment { get; set; } = "scans";

        public string ReportsSegment { get; set; } = "reports";
    }
}
