using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using SharpCompress.Common.Options;

namespace SharpCompress.Common;

public abstract class Entry : IEntry
{
    /// <summary>
    /// The File's 32 bit CRC Hash
    /// </summary>
    public abstract long Crc { get; }

    /// <summary>
    /// The string key of the file internal to the Archive.
    /// </summary>
    public abstract string? Key { get; }

    /// <summary>
    /// The target of a symlink entry internal to the Archive. Will be null if not a symlink.
    /// </summary>
    public abstract string? LinkTarget { get; }

    /// <summary>
    /// The compressed file size
    /// </summary>
    public abstract long CompressedSize { get; }

    /// <summary>
    /// The compression type
    /// </summary>
    public abstract CompressionType CompressionType { get; }

    /// <summary>
    /// The uncompressed file size
    /// </summary>
    public abstract long Size { get; }

    /// <summary>
    /// The entry last modified time in the archive, if recorded
    /// </summary>
    public abstract DateTime? LastModifiedTime { get; }

    /// <summary>
    /// The entry create time in the archive, if recorded
    /// </summary>
    public abstract DateTime? CreatedTime { get; }

    /// <summary>
    /// The entry last accessed time in the archive, if recorded
    /// </summary>
    public abstract DateTime? LastAccessedTime { get; }

    /// <summary>
    /// The entry time when archived, if recorded
    /// </summary>
    public abstract DateTime? ArchivedTime { get; }

    /// <summary>
    /// Entry is password protected and encrypted and cannot be extracted.
    /// </summary>
    public abstract bool IsEncrypted { get; }

    /// <summary>
    /// Entry is directory.
    /// </summary>
    public abstract bool IsDirectory { get; }

    /// <summary>
    /// Entry is split among multiple volumes
    /// </summary>
    public abstract bool IsSplitAfter { get; }

    public int VolumeIndexFirst => Parts.FirstOrDefault()?.Index ?? 0;
    public int VolumeIndexLast => Parts.LastOrDefault()?.Index ?? 0;

    /// <inheritdoc/>
    public override string ToString() => Key ?? "Entry";

    internal abstract IEnumerable<FilePart> Parts { get; }

    public bool IsSolid { get; set; }

    internal virtual void Close() { }

    internal virtual ChecksumDescriptor Checksum => default;

    internal virtual Stream WrapWithChecksumValidation(Stream source, ExtractionOptions options)
    {
        var checksum = Checksum;
        if (!checksum.IsAvailable)
        {
            return source;
        }

        return new ChecksumValidationStream(source, checksum, Key);
    }

    /// <summary>
    /// Entry file attribute.
    /// </summary>
    public virtual int? Attrib => throw new NotImplementedException();

    /// <summary>
    /// The options used when opening this entry's source (reader or archive).
    /// </summary>
    public IReaderOptions Options { get; protected set; }

    protected Entry(IReaderOptions readerOptions)
    {
        Options = readerOptions;
    }
}
