using System.Net.NetworkInformation;

namespace skyscraper8.GSE.GSE;

public abstract class GseLabel
{
    public abstract int Length { get; }
    public abstract string ToString();
    
    public abstract int LabelTypeIndicator { get; }
    public abstract bool IsBroadcast();

    public abstract int GetHashCode();
    public abstract bool Equals(object? obj);

    public abstract long ToLong();
}

public class _6byteLabel : GseLabel
{
    public _6byteLabel(byte[] buffer)
    {
        MAC = new PhysicalAddress(buffer);
    }

    public _6byteLabel(PhysicalAddress macAddress)
    {
        MAC = macAddress;
    }

    public PhysicalAddress MAC { get; private set; }

    override public string ToString()
    {
        return MAC.ToString();
    }

    public override int Length => 6;
    public override int LabelTypeIndicator => 0;

    public static PhysicalAddress BROADCAST = new PhysicalAddress(new byte[] { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff });
    public override bool IsBroadcast()
    {
        return MAC.Equals(BROADCAST);
    }

	public override bool Equals(object? obj)
	{
		return obj is _6byteLabel label &&
			   EqualityComparer<PhysicalAddress>.Default.Equals(MAC, label.MAC);
	}

	public override int GetHashCode()
	{
		return HashCode.Combine(MAC);
	}

	public override long ToLong()
	{
		byte[] bytes = MAC.GetAddressBytes();
        long result = 0;
        for (int i = 0; i < bytes.Length; i++)
        {
			result = (result << 8);
			result += bytes[i];
        }
        return result;
	}
}

public class _3byteLabel : GseLabel
{
    public _3byteLabel(byte[] buffer)
    {
        this.buffer = buffer;
    }

    private byte[] buffer;

    public byte GroupId => buffer[0];

    public ushort LogonId
    {
        get
        {
            ushort result = buffer[1];
            result <<= 8;
            result += buffer[2];
            return result;
        }
    }

    public override string ToString()
    {
        return $"{nameof(GroupId)}: {GroupId}, {nameof(LogonId)}: {LogonId}";
    }

    override public int Length => 3;

    public override int LabelTypeIndicator => 1;
    public override bool IsBroadcast()
    {
        return buffer[1] == 0xff && buffer[2] == 0xff;
    }

	public override bool Equals(object? obj)
	{
		return obj is _3byteLabel label &&
			   GroupId == label.GroupId &&
			   LogonId == label.LogonId;
	}

	public override int GetHashCode()
	{
		return HashCode.Combine(GroupId, LogonId);
	}

	public override long ToLong()
	{
        long result = 0;
        result = buffer[0];
        result <<= 8;
        result = buffer[1];
        result <<= 8;
        result = buffer[2];
        result <<= 8;
        return result;
	}
}

public class BroadcastLabel : GseLabel
{
    private BroadcastLabel() {}

    override public string ToString()
    {
        return "<Broadcast>";
    }
    
    override public int Length => 0;

    private static BroadcastLabel _instance;
    public static BroadcastLabel GetInstance()
    {
        if (_instance == null)
        {
            _instance = new BroadcastLabel();
        }
        return _instance;
    }

    public override int LabelTypeIndicator => 2;

    public override bool IsBroadcast()
    {
        return true;
    }

	public override bool Equals(object? obj)
	{
		return obj is BroadcastLabel label;
	}

	public override int GetHashCode()
	{
		return 0;
	}

	public override long ToLong()
	{
        return long.MaxValue;
	}
}