using System;
using SharpCompress.Common;
using SharpCompress.Common.Options;
using SharpCompress.Compressors;
using SharpCompress.Providers;
using SharpCompress.Writers;
using D = SharpCompress.Compressors.Deflate;

namespace SharpCompress.Writers.GZip;

/// <summary>
/// Options for configuring GZip writer behavior.
/// </summary>
/// <remarks>
/// Use factory methods, property setters, or fluent helpers for creation:
/// <code>
/// var options = WriterOptions.ForGZip().WithLeaveStreamOpen(false).WithCompressionLevel(9);
/// </code>
/// </remarks>
public sealed record GZipWriterOptions : IWriterOptions
{
    private int _compressionLevel = (int)D.CompressionLevel.Default;

    /// <summary>
    /// The compression type (always GZip for this writer).
    /// </summary>
    public CompressionType CompressionType
    {
        get => CompressionType.GZip;
        set
        {
            if (value != CompressionType.GZip)
            {
                throw new ArgumentOutOfRangeException(
                    nameof(CompressionType),
                    value,
                    "GZipWriterOptions only supports CompressionType.GZip."
                );
            }
        }
    }

    /// <summary>
    /// The compression level to be used (0-9 for Deflate).
    /// </summary>
    public int CompressionLevel
    {
        get => _compressionLevel;
        set
        {
            CompressionLevelValidation.Validate(CompressionType.GZip, value);
            _compressionLevel = value;
        }
    }

    /// <summary>
    /// SharpCompress will keep the supplied streams open.  Default is true.
    /// </summary>
    public bool LeaveStreamOpen { get; set; } = true;

    /// <summary>
    /// Encoding to use for archive entry names.
    /// </summary>
    public IArchiveEncoding ArchiveEncoding { get; set; } = new ArchiveEncoding();

    /// <summary>
    /// An optional progress reporter for tracking compression operations.
    /// </summary>
    public IProgress<ProgressReport>? Progress { get; set; }

    /// <summary>
    /// Buffer size for writer stream copy operations.
    /// </summary>
    public int BufferSize { get; set; } = Constants.BufferSize;

    /// <summary>
    /// Registry of compression providers.
    /// Defaults to <see cref="CompressionProviderRegistry.Default" /> but can be replaced with custom implementations, such as
    /// System.IO.Compression for GZip on modern .NET.
    /// </summary>
    public CompressionProviderRegistry Providers { get; set; } =
        CompressionProviderRegistry.Default;

    /// <summary>
    /// When true, opts in to a format's optional parallel encode. No writer currently implements
    /// parallel encoding; reserved for future use. Default is false.
    /// </summary>
    public bool EnableParallelism { get; set; }

    /// <summary>
    /// Creates a new GZipWriterOptions instance with default values.
    /// </summary>
    public GZipWriterOptions() { }

    /// <summary>
    /// Creates a new GZipWriterOptions instance with the specified compression level.
    /// </summary>
    /// <param name="compressionLevel">The compression level (0-9).</param>
    public GZipWriterOptions(int compressionLevel)
    {
        CompressionLevel = compressionLevel;
    }

    /// <summary>
    /// Creates a new GZipWriterOptions instance with the specified Deflate compression level.
    /// </summary>
    /// <param name="compressionLevel">The Deflate compression level.</param>
    public GZipWriterOptions(D.CompressionLevel compressionLevel)
    {
        CompressionLevel = (int)compressionLevel;
    }

    // Note: Constructor with boolean leaveStreamOpen parameter removed.
    // Use the fluent WithLeaveStreamOpen() helper or object initializer instead:
    // new GZipWriterOptions() { LeaveStreamOpen = false }
    // or
    // WriterOptions.ForGZip().WithLeaveStreamOpen(false)

    /// <summary>
    /// Creates a new GZipWriterOptions instance from an existing WriterOptions instance.
    /// </summary>
    /// <param name="options">The WriterOptions to copy values from.</param>
    public GZipWriterOptions(WriterOptions options)
    {
        CompressionLevel = options.CompressionLevel;
        LeaveStreamOpen = options.LeaveStreamOpen;
        ArchiveEncoding = options.ArchiveEncoding;
        Progress = options.Progress;
        BufferSize = options.BufferSize;
        Providers = options.Providers;
    }

    /// <summary>
    /// Creates a new GZipWriterOptions instance from an existing IWriterOptions instance.
    /// </summary>
    /// <param name="options">The IWriterOptions to copy values from.</param>
    public GZipWriterOptions(IWriterOptions options)
    {
        CompressionLevel = options.CompressionLevel;
        LeaveStreamOpen = options.LeaveStreamOpen;
        ArchiveEncoding = options.ArchiveEncoding;
        Progress = options.Progress;
        BufferSize = options.BufferSize;
        Providers = options.Providers;
    }
}
