using System;
using System.IO;
using System.Linq;
using System.Text;

namespace AnotherReplayReader.ReplayFile
{
    internal enum ReplayFooterOption
    {
        SeekToFooter,
        CurrentlyAtFooter,
    }

    internal sealed class ReplayFooter
    {
        public const uint Terminator = 0x7FFFFFFF;
        public static readonly byte[] FooterString = Encoding.ASCII.GetBytes("RA3 REPLAY FOOTER");

        private readonly byte[] _data;

        public uint FinalTimeCode { get; }
        public TimeSpan ReplayLength => TimeSpan.FromSeconds(FinalTimeCode / Replay.FrameRate);

        public ReplayFooter(BinaryReader reader, ReplayFooterOption option)
        {
            var currentPosition = reader.BaseStream.Position;
            reader.BaseStream.Seek(-4, SeekOrigin.End);
            var footerLength = reader.ReadInt32();

            if (option == ReplayFooterOption.SeekToFooter)
            {
                currentPosition = reader.BaseStream.Length - footerLength;
            }

            reader.BaseStream.Seek(currentPosition, SeekOrigin.Begin);
            var footer = reader.ReadBytes(footerLength);

            if (footer.Length != footerLength || reader.BaseStream.Position != reader.BaseStream.Length)
            {
                throw new InvalidDataException("Invalid footer");
            }

            using var footerStream = new MemoryStream(footer);
            using var footerReader = new BinaryReader(footerStream);
            var footerString = footerReader.ReadBytes(17);
            if (!footerString.SequenceEqual(FooterString))
            {
                throw new InvalidDataException("Invalid footer, no footer string");
            }
            FinalTimeCode = footerReader.ReadUInt32();
            _data = footerReader.ReadBytes(footer.Length - 25);
            if (footerReader.ReadInt32() != footerLength)
            {
                throw new InvalidDataException();
            }
        }

        public ReplayFooter(uint finalTimeCode)
        {
            FinalTimeCode = finalTimeCode;
            _data = new byte[] { 0x02, 0x1A, 0x00, 0x00, 0x00 };
        }

        public float[]? TryGetKillDeathRatios()
        {
            if (_data.Length < 24)
            {
                return null;
            }

            var ratios = new float[6];
            using var stream = new MemoryStream(_data, _data.Length - 24, 24);
            using var reader = new BinaryReader(stream);
            for (var i = 0; i < ratios.Length; ++i)
            {
                ratios[i] = reader.ReadSingle();
            }
            return ratios;
        }

        public void WriteTo(BinaryWriter writer)
        {
            writer.Write(Terminator);
            writer.Write(FooterString);
            writer.Write(FinalTimeCode);
            writer.Write(_data);
            writer.Write(FooterString.Length + _data.Length + 8);
        }
    }


}