using System;
using System.IO;
using skyscraper5.Dvb;
using skyscraper5.Skyscraper.IO;

namespace skyscraper5.Mpeg2
{
    public class TsPacket
    {
        public TsPacket(byte[] buffer)
        {
            if (buffer.Length != 188)
                throw new ArgumentException("Invalid buffer length");
            
            if (buffer[0] != 0x47)
                throw new ArgumentException("Buffer is not a TS packet");

            rawPacket = buffer;

			TEI = (buffer[1] & 0x80) != 0;
            PayloadUnitStart = (buffer[1] & 0x40) != 0;
            TransportPriority = (buffer[1] & 0x20) != 0;
            PID = (uint)((buffer[1] & 0x1f) << 8) | buffer[2];
            TSC = ((buffer[3] & 0xc0) >> 6);
            int AdaptionFieldControl = ((buffer[3] & 0x30) >> 4);
            Continuity = (byte)(buffer[3] & 0x0f);
            bool hasAdaptionField = (AdaptionFieldControl & 0x02) != 0;
            bool hasPayloadField = (AdaptionFieldControl & 0x01) != 0;

            int ptr = 4; 
            if (hasAdaptionField)
            {
                byte adaptionFieldLength = buffer[ptr++];
                int maxLength = 188 - ptr;
                if (adaptionFieldLength > maxLength)
                {
	                TEI = true;
	                return;
                }
                Span<byte> adaptionField = buffer.AsSpan(ptr, adaptionFieldLength);
                ptr += adaptionFieldLength;
                AdaptionField = new TsAdaptionField(adaptionField, TEI);
            }

            if (hasPayloadField)
            {
                PayloadOffset = ptr;
            }
        }

        public byte Continuity { get; set; }

        public int TSC { get; set; }

        public uint PID { get; set; }

        public bool TransportPriority { get; set; }

        public bool PayloadUnitStart { get; set; }

        public bool TEI { get; set; }
        
        public TsAdaptionField AdaptionField { get; set; }

        private int PayloadOffset;
        private byte[] rawPacket;
        
        public Span<byte> GetPayload()
        {
            if (PayloadOffset == 0)
                return null;
                
            return rawPacket.AsSpan(PayloadOffset);
        }

        public void SetUnscrambled(byte[] unscrambled)
        {
            throw new NotSupportedException("We aren't doing anything illegal, m'kay?");
        }
        
        public byte[] GetRawPacket()
        {
            return rawPacket;
        }
    }
}
