using System;
using System.IO;

namespace SharpCompress.Common.Rar.Headers;

internal class MarkHeader : IRarHeader
{
    private const int MAX_SFX_SIZE = 0x80000 - 16; //archive.cpp line 136

    internal bool OldNumberingFormat { get; private set; }

    public bool IsRar5 { get; }

    private MarkHeader(bool isRar5) => IsRar5 = isRar5;

    public HeaderType HeaderType => HeaderType.Mark;

    private static byte GetByte(Stream stream)
    {
        var b = stream.ReadByte();
        if (b != -1)
        {
            return (byte)b;
        }
        throw new EndOfStreamException();
    }

    public static MarkHeader Read(Stream stream, bool leaveStreamOpen, bool lookForHeader)
    {
        var maxScanIndex = lookForHeader ? MAX_SFX_SIZE : 0;
        try
        {
            var start = -1;
            var b = GetByte(stream);
            start++;
            while (start <= maxScanIndex)
            {
                // Rar old signature: 52 45 7E 5E
                // Rar4 signature:    52 61 72 21 1A 07 00
                // Rar5 signature:    52 61 72 21 1A 07 01 00
                if (b == 0x52)
                {
                    b = GetByte(stream);
                    start++;
                    if (b == 0x61)
                    {
                        b = GetByte(stream);
                        start++;
                        if (b != 0x72)
                        {
                            continue;
                        }

                        b = GetByte(stream);
                        start++;
                        if (b != 0x21)
                        {
                            continue;
                        }

                        b = GetByte(stream);
                        start++;
                        if (b != 0x1a)
                        {
                            continue;
                        }

                        b = GetByte(stream);
                        start++;
                        if (b != 0x07)
                        {
                            continue;
                        }

                        b = GetByte(stream);
                        start++;
                        if (b == 1)
                        {
                            b = GetByte(stream);
                            start++;
                            if (b != 0)
                            {
                                continue;
                            }

                            return new MarkHeader(true); // Rar5
                        }
                        else if (b == 0)
                        {
                            return new MarkHeader(false); // Rar4
                        }
                    }
                    else if (b == 0x45)
                    {
                        b = GetByte(stream);
                        start++;
                        if (b != 0x7e)
                        {
                            continue;
                        }

                        b = GetByte(stream);
                        start++;
                        if (b != 0x5e)
                        {
                            continue;
                        }

                        throw new InvalidFormatException(
                            "Rar format version pre-4 is unsupported."
                        );
                    }
                }
                else
                {
                    b = GetByte(stream);
                    start++;
                }
            }
        }
        catch (Exception e)
        {
            if (!leaveStreamOpen)
            {
                stream.Dispose();
            }
            throw new InvalidFormatException("Error trying to read rar signature.", e);
        }

        throw new InvalidFormatException("Rar signature not found");
    }
}
