using QtCNETAPI.Dtos.User;
using QtCNETAPI.Services.ApiService;
using QtCNETAPI.Services.GatewayService;
using QtCNETAPI.Events;
using QtCNETAPI.Models;
using qtc_net_client_2.Forms;
using qtc_net_client_2.Services;
using qtc_net_client_2.ClientModel;

namespace qtc_net_client_2
{
    public partial class Main : Form
    {
        private IApiService _apiService;
        private IGatewayService _gatewayService;
        private AudioService AudioService = new();

        private List<Room> RoomList = [];
        private List<UserInformationDto> OnlineUsers = [];
        private List<UserInformationDto> Contacts = [];
        public Main(IApiService apiService, IGatewayService gatewayService)
        {
            _apiService = apiService;
            _gatewayService = gatewayService;

            InitializeComponent();
        }

        private async void frmMain_Load(object sender, EventArgs e)
        {
            // start request notif blink task
            Thread blinkThread = new Thread(async () => await StartRequestNotifBlankLoop(lblRequestNotif));
            blinkThread.Start();

            // check if client is already logged in
            if (_apiService.CurrentUser == null)
            {
                // not logged in, load the login form
                Login frmLogin = new Login(_apiService);
                var result = frmLogin.ShowDialog();

                if (result == DialogResult.OK)
                    await OnSuccessfulLogin();
            }
        }

        private async void llblSignIn_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            // just reshow the login dialog lol
            Login frmLogin = new Login(_apiService);
            var result = frmLogin.ShowDialog();

            if (result == DialogResult.OK)
                await OnSuccessfulLogin();
        }

        private async void lbRooms_DoubleClick(object sender, EventArgs e)
        {
            if (lbRooms.SelectedItems.Count > 0)
            {
                string? selectedRoom = (string?)lbRooms.SelectedItems[lbRooms.SelectedItems.Count - 1];
                if (selectedRoom != null)
                {
                    if (selectedRoom == "Lobby")
                    {
                        // join lobby
                        if (!_gatewayService.InLobby) await _gatewayService.JoinLobbyAsync();

                        Chat frmChat = new Chat(_gatewayService, _apiService);
                        frmChat.Show();
                        return;
                    }

                    // join the room
                    Room? room = RoomList.FirstOrDefault(e => e.Name == selectedRoom);
                    if (room != null)
                    {
                        if (_gatewayService.CurrentRoom != room) await _gatewayService.JoinRoomAsync(room);

                        Chat frmChat = new Chat(_gatewayService, _apiService);
                        frmChat.Show();
                    }
                }
            }
        }

        private void pbUserPfp_Click(object sender, EventArgs e)
        {
            var args = (MouseEventArgs)e;
            if (args.Button == MouseButtons.Right) return;

            Thread t = new Thread(new ThreadStart(async () =>
            {
                using (OpenFileDialog openFileDialog = new OpenFileDialog())
                {
                    openFileDialog.InitialDirectory = Environment.CurrentDirectory;
                    openFileDialog.Title = "Select New Profile Picture";
                    openFileDialog.Filter = "Image Files (*.png, *.jpg)|*.png;*.jpg";

                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        // upload to server with api endpoint
                        var res = await _apiService.UpdateUserProfilePic(openFileDialog.FileName);

                        if (res.Success)
                        {
                            // update profile pic in ui
                            var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
                            if (pfpRes.Success && pfpRes.Data != null)
                            {
                                using (var ms = new MemoryStream(pfpRes.Data))
                                {
                                    pbUserPfp.Image = Image.FromStream(ms);
                                    ms.Dispose();
                                }
                            }
                        }
                    }
                }
            }));

            t.SetApartmentState(ApartmentState.STA);
            t.Start();
        }

        private void llblSignOut_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (MessageBox.Show("Are You Sure You Want To Sign Out?\nThis Deletes Your session.token, Requiring You To Sign In Again", "are you sure...?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes)
            {
                File.Delete("./session.token");
                Environment.Exit(0);
            }
        }

        private async void lbOnlineUsers_DoubleClick(object sender, EventArgs e)
        {
            if (lbOnlineUsers.SelectedItems.Count > 0)
            {
                string? selectedUser = (string?)lbOnlineUsers.SelectedItems[lbOnlineUsers.SelectedItems.Count - 1];

                if (selectedUser != null)
                {
                    // get user info and open profile dialog
                    var user = OnlineUsers.FirstOrDefault(e => e.Username == selectedUser);
                    var res = await _apiService.GetUserInformationAsync(user!.Id);
                    var pfpRes = await _apiService.GetUserProfilePic(user!.Id);

                    if (res.Data != null && res.Success)
                    {
                        Profile frmProfile = new Profile(res.Data, pfpRes, _apiService, _gatewayService);
                        frmProfile.ShowDialog();
                    }
                }
            }
        }

        private void llblEditProfile_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            ProfileEdit frmProfileEdit = new ProfileEdit(_apiService);
            var dialogResult = frmProfileEdit.ShowDialog();
            if (dialogResult == DialogResult.OK)
            {
                MessageBox.Show("If you updated your username, hit the refresh button to see it update on your lists.\nThe top username will not update until you restart your client.");
            }
        }

        private async void lvContacts_DoubleClick(object sender, EventArgs e)
        {
            if (lvContacts.SelectedItems.Count > 0)
            {
                string? selectedUser = (string?)lvContacts.SelectedItems[lvContacts.SelectedItems.Count - 1].Text;

                if (selectedUser != null)
                {
                    // split from [ if it exists
                    if (selectedUser.Contains('[')) selectedUser = selectedUser.Split('[', options: StringSplitOptions.TrimEntries)[0];

                    // get user info and open profile dialog
                    var user = Contacts.FirstOrDefault(e => e.Username == selectedUser);
                    var res = await _apiService.GetUserInformationAsync(user!.Id);
                    var pfpRes = await _apiService.GetUserProfilePic(user!.Id);

                    if (res.Data != null && res.Success)
                    {
                        Profile frmProfile = new Profile(res.Data, pfpRes, _apiService, _gatewayService);
                        frmProfile.ShowDialog();
                    }
                }
            }
        }

        private async void btnRefresh_Click(object sender, EventArgs e)
        {
            // refresh all
            await RefreshContactsList();
            await RefreshRoomsList();
            await RefreshOnlineUsersList();
        }

        private void frmMain_Resize(object sender, EventArgs e)
        {
            if (WindowState == FormWindowState.Minimized) Hide();
        }

        private void niMain_DoubleClick(object sender, EventArgs e)
        {
            Show();
            WindowState = FormWindowState.Normal;
        }

        private async void frmMain_FormClosed(object sender, FormClosedEventArgs e)
        {
            DialogResult = DialogResult.OK;

            // ensure the gateway stops the connection and disposes properly
            await _gatewayService.StopAsync();
            await _gatewayService.DisposeAsync();
        }

        private async void ctxmChangeStatus_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (e.ClickedItem != null)
            {
                UserStatus userStatus = UserStatus.Unknown;
                switch (e.ClickedItem.Name)
                {
                    case "onlineToolStripMenuItem":
                        userStatus = UserStatus.Online;
                        onlineToolStripMenuItem.Checked = true;
                        awayToolStripMenuItem.Checked = false;
                        doNotDisturbToolStripMenuItem.Checked = false;
                        invisibleToolStripMenuItem.Checked = false;
                        break;
                    case "awayToolStripMenuItem":
                        userStatus = UserStatus.Away;
                        onlineToolStripMenuItem.Checked = false;
                        awayToolStripMenuItem.Checked = true;
                        doNotDisturbToolStripMenuItem.Checked = false;
                        invisibleToolStripMenuItem.Checked = false;
                        break;
                    case "doNotDisturbToolStripMenuItem":
                        userStatus = UserStatus.DoNotDisturb;
                        onlineToolStripMenuItem.Checked = false;
                        awayToolStripMenuItem.Checked = false;
                        doNotDisturbToolStripMenuItem.Checked = true;
                        invisibleToolStripMenuItem.Checked = false;
                        break;
                    case "invisibleToolStripMenuItem":
                        userStatus = UserStatus.Offline;
                        onlineToolStripMenuItem.Checked = false;
                        awayToolStripMenuItem.Checked = false;
                        doNotDisturbToolStripMenuItem.Checked = false;
                        invisibleToolStripMenuItem.Checked = true;
                        break;
                }

                // set it
                await _gatewayService.UpdateStatus((int)userStatus);
            }
        }

        private void btnAddRoom_Click(object sender, EventArgs e)
        {
            CreateRoom createRoom = new CreateRoom(_apiService);
            createRoom.ShowDialog();
        }

        private async void llblClaimSpin_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            TokenJackpotSpinner tokenJackpotSpinner = new TokenJackpotSpinner();
            var frmResult = tokenJackpotSpinner.ShowDialog();

            if (frmResult == DialogResult.OK && tokenJackpotSpinner.TokensWon > 0)
            {
                // claim
                var result = await _apiService.AddCurrencyToCurrentUser(tokenJackpotSpinner.TokensWon, true);
                if (result.Success)
                {
                    lblCurrencyAmount.Text = (_apiService.CurrentUser.CurrencyAmount + tokenJackpotSpinner.TokensWon).ToString();
                    llblClaimSpin.Visible = false;
                }
                else MessageBox.Show("We Were Unable To Claim Your Prize At This Time. Please Try Again Later.", "Uh Oh.", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private async Task OnSuccessfulLogin()
        {
            // double check
            if (_apiService.CurrentUser != null && _apiService.SessionToken != null)
            {
                // start gateway connection
                await _gatewayService.StartAsync();

                // subscribe to gateway events
                _gatewayService.OnServerReconnecting += _gatewayService_OnServerReconnecting;
                _gatewayService.OnServerReconnected += _gatewayService_OnServerReconnected;
                _gatewayService.OnServerDisconnect += _gatewayService_OnServerDisconnect;
                _gatewayService.OnClientFunctionReceived += _gatewayService_OnClientFunctionReceived;
                _gatewayService.OnDirectMessageReceived += _gatewayService_OnDirectMessageReceived;
                _gatewayService.OnServerConfigReceived += _gatewayService_OnServerConfigReceived;

                if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
                {
                    // we are fully logged in, get current user profile pic and set up ui
                    llblSignIn.Visible = false;
                    lblWelcome.Text = $"Welcome, {_apiService.CurrentUser.Username}";
                    lblCurrencyAmount.Visible = true;
                    pbCurrencyIcon.Visible = true;
                    lblCurrencyAmount.Text = _apiService.CurrentUser.CurrencyAmount.ToString();
                    llblSignOut.Visible = true;
                    llblEditProfile.Visible = true;
                    tbcMain.Enabled = true;

                    var pfpRes = await _apiService.GetUserProfilePic(_apiService.CurrentUser.Id);
                    if (pfpRes.Success && pfpRes.Data != null)
                    {
                        using (var ms = new MemoryStream(pfpRes.Data))
                        {
                            pbUserPfp.Image = Image.FromStream(ms);
                            ms.Dispose();
                        }
                    }

                    await RefreshContactsList();
                    await RefreshRoomsList();
                    await RefreshOnlineUsersList();

                    // TODO - figure out server side why online status is invisible on login
                    _apiService.CurrentUser.Status = 1;

                    // set status context menu checked
                    UserStatus cuStatus = (UserStatus)_apiService.CurrentUser.Status;
                    switch (cuStatus)
                    {
                        case UserStatus.Online:
                            onlineToolStripMenuItem.Checked = true;
                            awayToolStripMenuItem.Checked = false;
                            doNotDisturbToolStripMenuItem.Checked = false;
                            invisibleToolStripMenuItem.Checked = false;
                            break;
                        case UserStatus.Away:
                            onlineToolStripMenuItem.Checked = false;
                            awayToolStripMenuItem.Checked = true;
                            doNotDisturbToolStripMenuItem.Checked = false;
                            invisibleToolStripMenuItem.Checked = false;
                            break;
                        case UserStatus.DoNotDisturb:
                            onlineToolStripMenuItem.Checked = false;
                            awayToolStripMenuItem.Checked = false;
                            doNotDisturbToolStripMenuItem.Checked = true;
                            invisibleToolStripMenuItem.Checked = false;
                            break;
                        case UserStatus.Offline:
                            onlineToolStripMenuItem.Checked = false;
                            awayToolStripMenuItem.Checked = false;
                            doNotDisturbToolStripMenuItem.Checked = false;
                            invisibleToolStripMenuItem.Checked = true;
                            break;
                    }

                    if (_apiService.CurrentUser.Role == "Admin") btnAddRoom.Enabled = true;
                    else btnAddRoom.Enabled = false;

                    var current = DateTime.UtcNow;
                    if (current > _apiService.CurrentUser.LastCurrencySpin.ToUniversalTime() || _apiService.CurrentUser.LastCurrencySpin == new DateTime()) llblClaimSpin.Visible = true;
                    else llblClaimSpin.Visible = false;
                }
            }
        }

        private async Task RefreshOnlineUsersList()
        {
            if (InvokeRequired)
            {
                await Invoke(async delegate ()
                {
                    lbOnlineUsers.Items.Clear();
                    var usersOnlineRes = await _apiService.GetOnlineUsersAsync();
                    if (usersOnlineRes.Success && usersOnlineRes.Data != null)
                    {
                        foreach (var user in usersOnlineRes.Data)
                        {
                            lbOnlineUsers.Items.Add(user.Username);
                        }
                        OnlineUsers = usersOnlineRes.Data;
                    }
                });
                return;
            }

            lbOnlineUsers.Items.Clear();
            var usersOnlineRes = await _apiService.GetOnlineUsersAsync();
            if (usersOnlineRes.Success && usersOnlineRes.Data != null)
            {
                lbOnlineUsers.Items.Clear();
                foreach (var user in usersOnlineRes.Data)
                {
                    lbOnlineUsers.Items.Add(user.Username);
                }
                OnlineUsers = usersOnlineRes.Data;
            }
        }

        private async Task RefreshRoomsList()
        {
            if (InvokeRequired)
            {
                await Invoke(async delegate ()
                {
                    lbRooms.Items.Clear();
                    var roomsRes = await _apiService.GetAllRoomsAsync();
                    if (roomsRes.Success && roomsRes.Data != null)
                    {
                        foreach (var room in roomsRes.Data)
                        {
                            lbRooms.Items.Add(room.Name);
                        }
                        RoomList = roomsRes.Data;
                    }

                    // always add lobby room to rooms list
                    lbRooms.Items.Add("Lobby");
                });
                return;
            }

            lbRooms.Items.Clear();
            var roomsRes = await _apiService.GetAllRoomsAsync();
            if (roomsRes.Success && roomsRes.Data != null)
            {
                lbRooms.Items.Clear();
                foreach (var room in roomsRes.Data)
                {
                    lbRooms.Items.Add(room.Name);
                }
                RoomList = roomsRes.Data;
            }

            // always add lobby room to rooms list
            lbRooms.Items.Add("Lobby");
        }

        private async Task RefreshContactsList()
        {
            if (InvokeRequired)
            {
                await Invoke(async delegate ()
                {
                    lvContacts.Items.Clear();
                    Contacts.Clear();
                    lblRequestNotif.Visible = false;
                    var contactsRes = await _apiService.GetCurrentUserContacts();
                    if (contactsRes.Success && contactsRes.Data != null)
                    {
                        if (contactsRes.Data.Where(e => e.UserId == _apiService.CurrentUser!.Id && e.UserStatus == Contact.ContactStatus.AwaitingApprovalFromSelf).Count() >= 1)
                            lblRequestNotif.Visible = true;
                        else
                            lblRequestNotif.Visible = false;

                        foreach (var contact in contactsRes.Data)
                        {
                            ServiceResponse<UserInformationDto> user = null!;
                            if (contact.OwnerId == _apiService.CurrentUser!.Id)
                                user = await _apiService.GetUserInformationAsync(contact.UserId);
                            else if (contact.UserId == _apiService.CurrentUser!.Id)
                                user = await _apiService.GetUserInformationAsync(contact.OwnerId);

                            if (user.Data != null)
                            {
                                Contacts.Add(user.Data);
                                if (contact.OwnerId == _apiService.CurrentUser!.Id)
                                {
                                    switch (contact.OwnerStatus)
                                    {
                                        case Contact.ContactStatus.AwaitingApprovalFromOther:
                                            var lvi = lvContacts.Items.Add($"{user.Data.Username} [Request Sent]");
                                            await AddProfilePicToList(user.Data.Id);
                                            lvi.ImageKey = user.Data.Id;
                                            break;
                                        case Contact.ContactStatus.Accepted:
                                            var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
                                            await AddProfilePicToList(user.Data.Id);
                                            lvi2.ImageKey = user.Data.Id;
                                            break;
                                    }
                                }
                                else if (contact.UserId == _apiService.CurrentUser!.Id)
                                {
                                    switch (contact.UserStatus)
                                    {
                                        case Contact.ContactStatus.AwaitingApprovalFromSelf:
                                            var lvi = lvContacts.Items.Add($"{user.Data.Username} [Contact Request]");
                                            await AddProfilePicToList(user.Data.Id);
                                            lvi.ImageKey = user.Data.Id;
                                            AudioService.PlaySoundEffect("sndContactRequest");
                                            break;
                                        case Contact.ContactStatus.Accepted:
                                            var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
                                            await AddProfilePicToList(user.Data.Id);
                                            lvi2.ImageKey = user.Data.Id;
                                            break;
                                    }
                                }
                            }
                        }
                    }
                });
                return;
            }

            lvContacts.Items.Clear();
            Contacts.Clear();
            lblRequestNotif.Visible = false;
            var contactsRes = await _apiService.GetCurrentUserContacts();
            if (contactsRes.Success && contactsRes.Data != null)
            {
                if (contactsRes.Data.Where(e => e.UserId == _apiService.CurrentUser!.Id && e.UserStatus == Contact.ContactStatus.AwaitingApprovalFromSelf).Count() >= 1)
                    lblRequestNotif.Visible = true;
                else
                    lblRequestNotif.Visible = false;

                foreach (var contact in contactsRes.Data)
                {
                    ServiceResponse<UserInformationDto> user = null!;
                    if (contact.OwnerId == _apiService.CurrentUser!.Id)
                        user = await _apiService.GetUserInformationAsync(contact.UserId);
                    else if (contact.UserId == _apiService.CurrentUser!.Id)
                        user = await _apiService.GetUserInformationAsync(contact.OwnerId);

                    if (user.Data != null)
                    {
                        Contacts.Add(user.Data);
                        if (contact.OwnerId == _apiService.CurrentUser!.Id)
                        {
                            switch (contact.OwnerStatus)
                            {
                                case Contact.ContactStatus.AwaitingApprovalFromOther:
                                    var lvi = lvContacts.Items.Add($"{user.Data.Username} [Request Sent]");
                                    await AddProfilePicToList(user.Data.Id);
                                    lvi.ImageKey = user.Data.Id;
                                    break;
                                case Contact.ContactStatus.Accepted:
                                    var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
                                    await AddProfilePicToList(user.Data.Id);
                                    lvi2.ImageKey = user.Data.Id;
                                    break;
                            }
                        }
                        else if (contact.UserId == _apiService.CurrentUser!.Id)
                        {
                            switch (contact.UserStatus)
                            {
                                case Contact.ContactStatus.AwaitingApprovalFromSelf:
                                    var lvi = lvContacts.Items.Add($"{user.Data.Username} [Contact Request]");
                                    await AddProfilePicToList(user.Data.Id);
                                    lvi.ImageKey = user.Data.Id;
                                    AudioService.PlaySoundEffect("sndContactRequest");
                                    break;
                                case Contact.ContactStatus.Accepted:
                                    var lvi2 = lvContacts.Items.Add($"{user.Data.Username}");
                                    await AddProfilePicToList(user.Data.Id);
                                    lvi2.ImageKey = user.Data.Id;
                                    break;
                            }
                        }
                    }
                }
            }
        }

        private async Task StartRequestNotifBlankLoop(Label label)
        {
            while (true)
            {
                if (InvokeRequired && label.IsHandleCreated)
                {
                    await Invoke(async delegate ()
                    {
                        label.ForeColor = Color.Red;
                        await Task.Delay(500);
                        label.ForeColor = Color.Blue;
                        await Task.Delay(500);
                    });
                }
                else if (label.IsHandleCreated)
                {
                    label.ForeColor = Color.Red;
                    await Task.Delay(500);
                    label.ForeColor = Color.Blue;
                    await Task.Delay(500);
                }
            }
        }

        private async Task AddProfilePicToList(string userId)
        {
            var result = await _apiService.GetUserProfilePic(userId);
            if (result != null && result.Success && result.Data != null)
            {
                using (var ms = new MemoryStream(result.Data))
                {
                    ilProfilePics.Images.Add(userId, Image.FromStream(ms));
                    ms.Dispose();
                }
            }
        }

        private async void _gatewayService_OnServerDisconnect(object? sender, EventArgs e)
        {
            if (DialogResult == DialogResult.OK) return;

            var args = (ServerConnectionClosedEventArgs)e;
            string? error = string.Empty;
            if (args.Error != null) error = args.Error.Message;

            // disconnect can sometimes be caused by an expired JWT token, attempt connection restart
            await _gatewayService.StopAsync();
            await _gatewayService.StartAsync();

            if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
            { BeginInvoke(delegate () { Enabled = true; }); return; }

            ConnectionClosed frmConnectionClosed = new ConnectionClosed(error);
            var result = frmConnectionClosed.ShowDialog();

            if (result == DialogResult.OK)
            {
            // tell the gateway service to attempt reconnection
            Reconnect:
                if (_gatewayService.HubConnection != null)
                {
                    try
                    {
                        await _gatewayService.StopAsync();
                        await _gatewayService.StartAsync();
                        if (_gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
                            BeginInvoke(delegate () { Enabled = true; });
                    }
                    catch (HttpRequestException ex)
                    {
                        // reshow the dialog
                        frmConnectionClosed.Reason = ex.Message;
                        var result1 = frmConnectionClosed.ShowDialog();
                        if (result1 == DialogResult.OK) goto Reconnect;
                        else Environment.Exit(0);
                    }
                }
            }
            else Environment.Exit(0);
        }

        private void _gatewayService_OnServerReconnecting(object? sender, EventArgs e) => BeginInvoke(delegate () { Enabled = false; });
        private void _gatewayService_OnServerReconnected(object? sender, EventArgs e) => BeginInvoke(delegate () { Enabled = true; });

        private async void _gatewayService_OnClientFunctionReceived(object? sender, EventArgs e)
        {
            var args = (ClientFunctionEventArgs)e;

            switch (args.Function)
            {
                case "rul":
                    await RefreshOnlineUsersList();
                    break;
                case "rr":
                    await RefreshRoomsList();
                    break;
                case "rcl":
                    await RefreshContactsList();
                    break;
            }
        }

        private async void _gatewayService_OnServerConfigReceived(object? sender, EventArgs e)
        {
            var args = (ServerConfigEventArgs)e;

            if (args.ServerConfig != null)
            {
                if (args.ServerConfig.IsDown)
                {
                    MessageBox.Show($"Sorry, This Server Is Currently Down.\nMessage: {args.ServerConfig.IsDownMessage}\n\nPlease Try Again Later");

                    if (_gatewayService.HubConnection != null && _gatewayService.HubConnection.State == Microsoft.AspNetCore.SignalR.Client.HubConnectionState.Connected)
                    {
                        await _gatewayService.StopAsync();
                        await _gatewayService.DisposeAsync();
                    }
                    Environment.Exit(0);
                }

                BeginInvoke(delegate () { Text = $"QtC.NET Client = Connected To {args.ServerConfig.Name}"; });
            }
        }

        private void _gatewayService_OnDirectMessageReceived(object? sender, EventArgs e)
        {
            var args = (DirectMessageEventArgs)e;

            DirectMessage? existingForm = (DirectMessage?)Application.OpenForms.Cast<Form>().FirstOrDefault(e => e.Name == "DirectMessage");
            if (existingForm != null && existingForm.User.Id == args.User.Id)
            {
                // we want to just add to its text box
                existingForm.Messages.Add($"[{args.User.Username}] {args.Message.Content}\n");
            }
            else
            {
                // start a new form
                DirectMessage frmDirectMessage = new DirectMessage(_gatewayService, _apiService, args.User, args.Message);
                Task.Run(frmDirectMessage.ShowDialog);
            }
        }
    }
}
