using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2.Descriptors;
using skyscraper5.Skyscraper.IO;
using skyscraper5.T2MI;
using skyscraper8.GSE;
using skyscraper8.Skyscraper.Scraper;

namespace skyscraper8.GS.SiminnRadiomidun
{
	internal class SiminnRadiomidunReader : IMisHandler
	{
		public SiminnRadiomidunReader(GsContextDto context)
		{
			this.packetQueue = new Queue<Tuple<BBHeader,MemoryStream>>();
			this.isInSync = false;
			this.subTsKey = new SiminnRadiomidunSubTsIdentifier(context.GetMisId());
			this.Context = context;
		}

		private bool isInSync;
		private Queue<Tuple<BBHeader, MemoryStream>> packetQueue;
		private MemoryStream currentItem;
		private SiminnRadiomidunSubTsIdentifier subTsKey;

		public long PacketQueueSize
		{
			get
			{
				if (packetQueue == null)
					return 0;

				return packetQueue.Select(x => x.Item2.Length).Sum();
			}
		}

		public GsContextDto Context { get; set; }

		public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
		{
			if (packetQueue == null)
				packetQueue = new Queue<Tuple<BBHeader, MemoryStream>>();

			packetQueue.Enqueue(new Tuple<BBHeader, MemoryStream>(bbHeader,new MemoryStream(readOnlySpan.Slice(0,bbHeader.DataFieldLength).ToArray(), true)));

			while (PacketQueueSize > 8192)
			{
				if (!isInSync)
				{
					Tuple<BBHeader, MemoryStream> dequeue = packetQueue.Dequeue();
					currentItem = dequeue.Item2;
					currentItem.Position = dequeue.Item1.SyncD;
					isInSync = true;
				}

				byte[] outputPacketBuffer = new byte[188];
				int result = currentItem.Read(outputPacketBuffer, 0, 188);
				if (result == 188)
				{
					OutputPacket(outputPacketBuffer);
				}
				else
				{
					int bytesNeeded = 188 - result;
					Tuple<BBHeader, MemoryStream> dequeue = packetQueue.Dequeue();
					if (bytesNeeded == dequeue.Item1.SyncD)
					{
						//We're still in sync!
						syncSucess++;
						currentItem = dequeue.Item2;
						currentItem.Read(outputPacketBuffer, result, bytesNeeded);
						OutputPacket(outputPacketBuffer);
					}
					else
					{
						//sync loss, let's discard the packet
						syncFail++;
						currentItem = dequeue.Item2;
						currentItem.Position = dequeue.Item1.SyncD;
					}
				}
			}
		}

		private ulong syncSucess, syncFail;
		private void OutputPacket(byte[] buffer)
		{
			buffer[0] = 0x47;
			Context.TsOutput.OnSubTsPacket(subTsKey, buffer);
		}
	}
}
