using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Net.Sockets;
using System.IO;

namespace Passer.Control {

    public class Client {
        //public ConnectionMethod connection;
        public UdpClient udpClient;
        public string ipAddress;
        public int port;
        public Stream dataStream;

        public byte networkId = 0;

        public readonly ConcurrentQueue<IMessage> messageQueue = new();

        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>();

        //// These static functions are deprecated
        //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 Client() {

        //}

        public Client(UdpClient udpClient, int port) {
            this.udpClient = udpClient;
            this.ipAddress = null;
            this.port = port;
            this.dataStream = new EchoStream();
            clients.Add(this);
        }

        public virtual void ProcessMessages() {
            while (this.messageQueue.TryDequeue(out IMessage msg))
                ProcessMessage(msg);
        }

        public void ProcessMessage(IMessage msg) {
            switch (msg) {
                case ClientMsg clientMsg:
                    ProcessClient(clientMsg);
                    break;
                case NetworkIdMsg networkId:
                    ProcessNetworkId(networkId);
                    break;
                case InvestigateMsg investigate:
                    ProcessInvestigate(investigate);
                    break;
                case ThingMsg thing:
                    ProcessThing(thing);
                    break;
                case NameMsg name:
                    ProcessName(name);
                    break;
                case ModelUrlMsg modelUrl:
                    ProcessModelUrl(modelUrl);
                    break;
                case PoseMsg pose:
                    ProcessPose(pose);
                    break;
                case CustomMsg custom:
                    ProcessCustom(custom);
                    break;
                case TextMsg text:
                    ProcessText(text);
                    break;
                case DestroyMsg destroy:
                    ProcessDestroy(destroy);
                    break;
            }
        }

        protected virtual void ProcessClient(ClientMsg client) { }

        protected virtual void ProcessNetworkId(NetworkIdMsg networkId) { }

        protected virtual void ProcessInvestigate(InvestigateMsg investigate) { }

        protected virtual void ProcessThing(ThingMsg thing) { }

        protected virtual void ProcessName(NameMsg name) { }

        protected virtual void ProcessModelUrl(ModelUrlMsg modelUrl) { }

        protected virtual void ProcessPose(PoseMsg pose) { }

        protected virtual void ProcessCustom(CustomMsg custom) { }

        protected virtual void ProcessText(TextMsg text) { }

        protected virtual void ProcessDestroy(DestroyMsg destroy) { }
    }
}