using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Newtonsoft.Json;

namespace Project
{
    /// <summary>
    /// Background chat client service with auto-reconnect
    /// </summary>
    public class ChatClientService : IDisposable
    {
        private TcpClient tcpClient;
        private NetworkStream stream;
        private Thread receiveThread;
        private Thread reconnectThread;
        private bool isRunning;
        private bool isConnected;

        private string serverIp;
        private int serverPort;
        private string nickName;
        private string employeeId;
        private string hostName;
        private string userGroup;

        /// <summary>Connection status changed event</summary>
        public event EventHandler<bool> ConnectionStatusChanged;

        /// <summary>Message received event</summary>
        public event EventHandler<ChatMessage> MessageReceived;

        /// <summary>Connection status</summary>
        public bool IsConnected => isConnected;

        /// <summary>User nickname</summary>
        public string NickName => nickName;

        /// <summary>User employee ID</summary>
        public string EmployeeId => employeeId;

        /// <summary>User group</summary>
        public string UserGroup => userGroup;

        public ChatClientService(string serverIp, int serverPort)
        {
            this.serverIp = serverIp;
            this.serverPort = serverPort;
            this.hostName = System.Net.Dns.GetHostName();
        }

        /// <summary>
        /// Start background service
        /// </summary>
        public void Start(string nickName, string employeeId, string userGroup)
        {
            if (isRunning)
                return;

            this.nickName = nickName;
            this.employeeId = employeeId;
            this.userGroup = userGroup;
            isRunning = true;

            // Start reconnect thread
            reconnectThread = new Thread(ReconnectLoop)
            {
                IsBackground = true,
                Name = "ChatReconnectThread"
            };
            reconnectThread.Start();
        }

        /// <summary>
        /// Stop background service
        /// </summary>
        public void Stop()
        {
            isRunning = false;
            Disconnect();

            try
            {
                reconnectThread?.Join(2000);
                receiveThread?.Join(2000);
            }
            catch { }
        }

        /// <summary>
        /// Auto-reconnect loop
        /// </summary>
        private void ReconnectLoop()
        {
            while (isRunning)
            {
                if (!isConnected)
                {
                    try
                    {
                        Connect();
                    }
                    catch
                    {
                        // Retry after 5 seconds
                        Thread.Sleep(5000);
                    }
                }
                else
                {
                    Thread.Sleep(1000);
                }
            }
        }

        /// <summary>
        /// Connect to server
        /// </summary>
        private void Connect()
        {
            try
            {
                tcpClient = new TcpClient();
                tcpClient.Connect(serverIp, serverPort);
                stream = tcpClient.GetStream();
                isConnected = true;

                // Notify connection status
                ConnectionStatusChanged?.Invoke(this, true);

                // Send connect message
                var connectMsg = new ChatMessage
                {
                    Type = MessageType.Connect,
                    NickName = nickName,
                    EmployeeId = employeeId,
                    HostName = hostName,
                    UserGroup = userGroup,
                    Timestamp = DateTime.Now
                };
                SendMessage(connectMsg);

                // Start receive thread
                receiveThread = new Thread(ReceiveLoop)
                {
                    IsBackground = true,
                    Name = "ChatReceiveThread"
                };
                receiveThread.Start();
            }
            catch
            {
                Disconnect();
                throw;
            }
        }

        /// <summary>
        /// Disconnect from server
        /// </summary>
        private void Disconnect()
        {
            if (!isConnected)
                return;

            isConnected = false;

            try
            {
                stream?.Close();
                tcpClient?.Close();
            }
            catch { }

            // Notify connection status
            ConnectionStatusChanged?.Invoke(this, false);
        }

        /// <summary>
        /// Message receive loop
        /// </summary>
        private void ReceiveLoop()
        {
            byte[] buffer = new byte[8192];

            try
            {
                while (isRunning && isConnected && tcpClient.Connected)
                {
                    int bytesRead = stream.Read(buffer, 0, buffer.Length);
                    if (bytesRead == 0)
                    {
                        // Connection closed
                        break;
                    }

                    string jsonData = Encoding.UTF8.GetString(buffer, 0, bytesRead);
                    var message = JsonConvert.DeserializeObject<ChatMessage>(jsonData);

                    if (message != null)
                    {
                        // Filter messages by group (dev can see all)
                        // UserListResponse and system messages should always be received
                        if (userGroup == "dev" ||
                            message.UserGroup == userGroup ||
                            message.Type == MessageType.Notice ||
                            message.Type == MessageType.UserListResponse ||
                            message.Type == MessageType.Pong)
                        {
                            MessageReceived?.Invoke(this, message);
                        }
                    }
                }
            }
            catch
            {
                // Connection error
            }
            finally
            {
                Disconnect();
            }
        }

        /// <summary>
        /// Send message
        /// </summary>
        public bool SendMessage(ChatMessage message)
        {
            if (!isConnected || tcpClient == null || !tcpClient.Connected)
                return false;

            try
            {
                message.NickName = nickName;
                message.UserGroup = userGroup;
                message.Timestamp = DateTime.Now;

                string jsonData = JsonConvert.SerializeObject(message);
                byte[] data = Encoding.UTF8.GetBytes(jsonData);
                stream.Write(data, 0, data.Length);
                stream.Flush();
                return true;
            }
            catch
            {
                Disconnect();
                return false;
            }
        }

        /// <summary>
        /// Send chat message
        /// </summary>
        public bool SendChatMessage(string content)
        {
            var message = new ChatMessage
            {
                Type = MessageType.Chat,
                Content = content
            };
            return SendMessage(message);
        }

        /// <summary>
        /// Request user list
        /// </summary>
        public bool RequestUserList()
        {
            var message = new ChatMessage
            {
                Type = MessageType.UserListRequest
            };
            return SendMessage(message);
        }

        public void Dispose()
        {
            Stop();
        }
    }
}
