using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Passer.Control {
public class Client {
	//public ConnectionMethod connection;
	public UdpClient udpClient;
	public string ipAddress;
	public int port;

	public byte networkId;

	public static Client GetClient(string ipAddress, int port) {
		foreach (Client c in clients) {
			if (c.ipAddress == ipAddress && c.port == port)
				return c;
		}
		return null;
	}
	static public List<Client> clients = new List<Client>();

	public static Client NewClient() {
		Client client = new();
		clients.Add(client);
		client.networkId = 0;

		return client;
	}

	public static Client NewUDPClient(UdpClient udpClient, string ipAddress, int port) {
		Client client = NewClient();
		client.ipAddress = null;
		client.port = port;
		client.udpClient = udpClient;
		return client;
	}
}

public class IMessage {
	public IMessage() { }
	public IMessage(byte[] data) {
		Deserialize(data);
	}

	public virtual byte[] Serialize() { return null; }
	public virtual void Deserialize(byte[] data) { }
	
	public static void SendMsg(Client client, byte[] data) {
		if (client.ipAddress != null)
			client.udpClient.Send(data, data.Length, client.ipAddress, client.port);
		else
			;//Debug.Log("Unknown client");
	}
}

#region Client

class ClientMsg : IMessage {
	public const byte length = 2;
	public byte clientId;

	public ClientMsg(byte[] data) : base(data) { }
	public override void Deserialize(byte[] data) {
		base.Deserialize(data);
		uint ix = 0;
		clientId = data[ix++];
	}
	
	protected async Task<bool> Receive(Stream dataStream, Client client, byte packetSize) {
		if (packetSize != ClientMsg.length) {
			//Debug.LogWarning($"Client msg size invalid: {packetSize}");
			return false;
		}

		byte[] buffer = new byte[packetSize - 1]; //  without msgId
		int byteCount = dataStream.Read(buffer, 0, packetSize - 1);
		while (byteCount < packetSize - 1) {
			// not all bytes have been read, wait and try again
			await Task.Delay(1);
			byteCount += dataStream.Read(buffer, byteCount, packetSize - 1 - byteCount);
		}

		ClientMsg msg = new(buffer);

		if (client.networkId == 0) {
			client.networkId = (byte)(Client.clients.Count);
			NetworkIdMsg.Send(client);
			//if (string.IsNullOrEmpty(sceneUrl) == false)
				//SendModelUrl(client, sceneUrl);
		}
		else if (msg.clientId == 0) {
			NetworkIdMsg.Send(client);
			//if (string.IsNullOrEmpty(sceneUrl) == false)
				//SendModelUrl(client, sceneUrl);
		}

		return true;
	}
}

#endregion Client

#region Network Id

class NetworkIdMsg : IMessage {
	public const byte Id = 0xA1;
	public const byte length = 2;
	
	public static void Send(Client client) {
		byte[] data = new byte[NetworkIdMsg.length];
		data[0] = NetworkIdMsg.Id;
		data[1] = client.networkId;
		SendMsg(client, data);
	}
}

#endregion Network Id
}