using System.Collections.Generic;
using System.Linq;

namespace InABox.DigitalMatter
{
    public class DMRecord : DMObject
    {
        private List<DMField> _fields = new();

        public ushort Length { get; set; }

        public uint Sequence { get; set; }

        public uint TimeStamp { get; set; }

        public byte LogReason { get; set; }

        public DMField[] Fields
        {
            get => _fields.ToArray();
            set => _fields = value.ToList();
        }

        protected override void DoDecode(IDMReadBuffer buffer)
        {
            //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("- Length: Size is [{0}]",BufferSize));
            Length = buffer.TakeUInt16();
            //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("- Sequence: Size is [{0}]", BufferSize));
            Sequence = buffer.TakeUInt32();
            //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("- TimeStamp: Size is [{0}]", BufferSize));
            TimeStamp = buffer.TakeUInt32();
            //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("- LogReason: Size is [{0}]", BufferSize));
            LogReason = buffer.TakeByte();

            _fields.Clear();

            int bytesTaken = 0;
            while (buffer.BufferSize > 0 && bytesTaken < Length)
            {
                var fieldid = buffer.PeekByte(0);
                var fieldsize = buffer.PeekByte(1) == 255 ? buffer.PeekUInt16(1) : buffer.PeekByte(1);
                //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("{0}: Field ID is [{1}] Size is [{2}]", _fields.Count, fieldid, fieldsize));
                var field = DMFactory.ParseField(new DMPartialReadBuffer(buffer, 0, buffer.BufferSize));
                _fields.Add(field);

                var bytesToTake = field.Length > 255 ? field.Length + 3 : field.Length + 2;
                buffer.TakeBytes(bytesToTake);

                bytesTaken += bytesToTake;
            }
            //Logger.Send(LogType.Information, Thread.CurrentThread.ManagedThreadId.ToString(), String.Format("- Done!: Size is [{0}]", BufferSize));
        }

        protected override void DoEncode(IDMWriteBuffer buffer)
        {
            buffer.AddUInt32(Sequence);
            buffer.AddUInt32(TimeStamp);
            buffer.AddByte(LogReason);

            foreach (var field in _fields)
                field.Encode(buffer);

            buffer.InsertUInt16(0, buffer.BufferSize);
        }

        public string Dump()
        {
            return $"[{string.Join(',', _fields.Select(x => x.Dump()))}]";
        }

        public IEnumerable<TField> GetFields<TField>() => 
            _fields.Where(x => x is TField).Cast<TField>();
    }
}