using System.IO;
using SharpCompress.Common;
using SharpCompress.Providers;

namespace SharpCompress.Common.Lzw;

internal sealed partial class LzwFilePart : FilePart
{
    private readonly Stream _stream;
    private readonly string? _name;
    private readonly CompressionProviderRegistry _compressionProviders;

    internal static LzwFilePart Create(
        Stream stream,
        IArchiveEncoding archiveEncoding,
        CompressionProviderRegistry compressionProviders
    )
    {
        var part = new LzwFilePart(stream, archiveEncoding, compressionProviders);

        // For non-seekable streams, we can't track position, so use 0 since the stream will be
        // read sequentially from its current position.
        part.EntryStartPosition = stream.CanSeek ? stream.Position : 0;
        return part;
    }

    private LzwFilePart(
        Stream stream,
        IArchiveEncoding archiveEncoding,
        CompressionProviderRegistry compressionProviders
    )
        : base(archiveEncoding)
    {
        _stream = stream;
        _name = DeriveFileName(stream);
        _compressionProviders = compressionProviders;
    }

    internal long EntryStartPosition { get; private set; }

    internal override string? FilePartName => _name;

    internal override Stream GetCompressedStream() =>
        _compressionProviders.CreateDecompressStream(CompressionType.Lzw, _stream);

    internal override Stream GetRawStream() => _stream;

    private static string? DeriveFileName(Stream stream)
    {
        // Unwrap SharpCompressStream to get to the underlying FileStream
        var unwrappedStream = stream;
        if (stream is SharpCompress.IO.IStreamStack streamStack)
        {
            unwrappedStream = streamStack.BaseStream();
        }

        // Try to derive filename from FileStream
        if (unwrappedStream is FileStream fileStream && !string.IsNullOrEmpty(fileStream.Name))
        {
            var fileName = Path.GetFileName(fileStream.Name);
            // Strip .Z extension if present
            if (fileName.EndsWith(".Z", System.StringComparison.OrdinalIgnoreCase))
            {
                return fileName.Substring(0, fileName.Length - 2);
            }
            return fileName;
        }
        // Default name for non-file streams
        return "data";
    }
}
