using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Docsis.MacManagement.BaselinePrivacyKeyManagementMessages;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;

namespace skyscraper5.Docsis.MacManagement
{
    [SkyscraperPlugin]
    [MacManagementMessageType(1,13)]
    public class PrivacyKeyManagementResponse : MacManagementMessage
    {
        public PrivacyKeyManagementResponse(PhysicalAddress source, PhysicalAddress destination, byte[] buffer) : base(source, destination, buffer)
        {
            MemoryStream ms = new MemoryStream(buffer, false);
            Code = ms.ReadUInt8();
            Identifier = ms.ReadUInt8();
            ushort length = ms.ReadUInt16BE();
            if (length > ms.GetAvailableBytes())
            {
                Valid = false;
                return;
            }

            byte[] subbuffer = ms.ReadBytes(length);

            switch (Code)
            {
                case 5: BpkmMessage = new AuthReply(subbuffer); break;
                case 8: BpkmMessage = new KeyReply(subbuffer); break;
                default:
                    if (Code >= 16 || Code <= 3)
                    {
                        Valid = false;
                        return;
                    }
                    //CM-SP-SECv4.0-I01-190815.pdf page 50
                    throw new NotImplementedException(String.Format("{0} {1}", nameof(Code), Code));
            }
            Valid = true;
        }

        public byte Identifier { get; private set; }

        public byte Code { get; private set; }

        public BpkmMessageObject BpkmMessage { get; private set; }

        public abstract class BpkmMessageObject
        {
            protected BpkmMessageObject(byte[] buffer)
            {
                MemoryStream ms = new MemoryStream(buffer, false);
                while (ms.GetAvailableBytes() >= 3)
                {
                    byte type = ms.ReadUInt8();
                    ushort length = ms.ReadUInt16BE();
                    byte[] value = ms.ReadBytes(length);
                    SetValue(type, value);
                }
            }

            protected abstract void SetValue(byte type, byte[] v);
        }
    }
}
