using UnityEngine;
using System.Net;
using System;
using System.Net.Sockets;
using System.Threading;

using NeonTea.Quakeball.TeaNet.Packets;

namespace NeonTea.Quakeball.TeaNet.Peers {
    /// <summary>Manager for the thread that listens from the given endpoint. Initiated with <see cref="Peer.StartListen(string, int)"/></summary>
    public class ListenerThread {
        private IPEndPoint EndPoint;
        private Thread Thread;
        private Peer Peer;

        public Connection LastSentConnection;

        private static int[] CONN_LOST_CODES = new int[] { 10054, 10051 };

        public ListenerThread(Peer peer, IPEndPoint endpoint) {
            EndPoint = endpoint;
            Peer = peer;
        }

        public bool Start() {
            if (Thread != null) {
                return false;
            }
            Thread t = new Thread(new ThreadStart(ListenThreadMethod));

            t.Start();
            Thread = t;
            return true;
        }

        public bool Stop() {
            if (Thread == null) {
                return false;
            }
            Thread.Abort();
            return true;
        }

        private void ListenThreadMethod() {
            try {
                while (Thread.CurrentThread.IsAlive) {
                    if (Peer.UdpClient.Available > 0) {
                        IPEndPoint Listened = new IPEndPoint(EndPoint.Address, EndPoint.Port);
                        ByteBuffer Buffer = new ByteBuffer();
                        try {
                            Buffer = new ByteBuffer(Peer.UdpClient.Receive(ref Listened));
                        } catch (SocketException e) {
                            if (Array.Exists(CONN_LOST_CODES, x => x == e.ErrorCode)) {
                                if (LastSentConnection != null) {
                                    LastSentConnection.Status = ConnectionStatus.Lost;
                                    Peer.MessageListener.Err($"Connection lost to {LastSentConnection.Endpoint}: {e.ToString()}");
                                }
                            } else {
                                Peer.MessageListener.Err($"Listener error: {e.ToString()}");
                            }
                        }
                        if (Buffer.ReadFingerprint(Peer.Fingerprint)) {
                            Peer.ConnectionManager.Handle(Listened, Buffer);
                        }
                    }
                }
            } catch (ThreadAbortException) {
                Peer.MessageListener.Message("Listener Thread stopped");
            }
        }
    }
}