using Dalamud.Bindings.ImGui;
using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using LightlessSync.API.Data.Enum;
using LightlessSync.API.Data.Extensions;
using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Services;
using LightlessSync.Services.LightFinder;
using LightlessSync.Services.Mediator;
using LightlessSync.UI.Models;
using LightlessSync.UI.Style;
using LightlessSync.Utils;
using LightlessSync.WebAPI;
using System;
using System.Numerics;

namespace LightlessSync.UI;

public class TopTabMenu
{
    private readonly ApiController _apiController;

    private readonly LightlessMediator _lightlessMediator;

    private readonly PairRequestService _pairRequestService;
    private readonly DalamudUtilService _dalamudUtilService;
    private readonly LightFinderService _lightFinderService;
    private readonly LightFinderScannerService _lightFinderScannerService;
    private readonly HashSet<string> _pendingPairRequestActions = new(StringComparer.Ordinal);
    private bool _pairRequestsExpanded; // useless for now
    private int _lastRequestCount;
    private readonly UiSharedService _uiSharedService;
    private readonly NotificationService _lightlessNotificationService;
    private string _filter = string.Empty;
    private int _globalControlCountdown = 0;
    private float _pairRequestsHeight = 150f;
    private string _pairToAdd = string.Empty;

    private SelectedTab _selectedTab = SelectedTab.None;
    private PairUiSnapshot? _currentSnapshot;

    public TopTabMenu(LightlessMediator lightlessMediator, ApiController apiController, UiSharedService uiSharedService, PairRequestService pairRequestService, DalamudUtilService dalamudUtilService, NotificationService lightlessNotificationService, LightFinderService lightFinderService, LightFinderScannerService lightFinderScannerService)
    {
        _lightlessMediator = lightlessMediator;
        _apiController = apiController;
        _pairRequestService = pairRequestService;
        _dalamudUtilService = dalamudUtilService;
        _uiSharedService = uiSharedService;
        _lightlessNotificationService = lightlessNotificationService;
        _lightFinderService = lightFinderService;
        _lightFinderScannerService = lightFinderScannerService;
    }

    private enum SelectedTab
    {
        None,
        Individual,
        Syncshell,
        Lightfinder,
        UserConfig,
        Settings
    }

    public string Filter
    {
        get => _filter;
        private set
        {
            if (!string.Equals(_filter, value, StringComparison.OrdinalIgnoreCase))
            {
                _lightlessMediator.Publish(new RefreshUiMessage());
            }

            _filter = value;
        }
    }
    private SelectedTab TabSelection
    {
        get => _selectedTab; set
        {
            _selectedTab = value;
        }
    }

    private PairUiSnapshot Snapshot => _currentSnapshot ?? throw new InvalidOperationException("Pair UI snapshot is not available outside of Draw.");

    public void Draw(PairUiSnapshot snapshot)
    {
        _currentSnapshot = snapshot;
        try
        {
            var availableWidth = ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X;
            var spacing = ImGui.GetStyle().ItemSpacing;
            var buttonX = (availableWidth - (spacing.X * 5)) / 6f;
            var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y;
            var buttonSize = new Vector2(buttonX, buttonY);
            const float buttonBorderThickness = 12f;
            var buttonRounding = ImGui.GetStyle().FrameRounding;
            var drawList = ImGui.GetWindowDrawList();
            var underlineColor = ImGui.GetColorU32(UIColors.Get("LightlessPurpleActive")); // ImGui.GetColorU32(ImGuiCol.Separator);
            var btncolor = ImRaii.PushColor(ImGuiCol.Button, ImGui.ColorConvertFloat4ToU32(new(0, 0, 0, 0)));

            ImGuiHelpers.ScaledDummy(spacing.Y / 2f);

            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                var x = ImGui.GetCursorScreenPos();
                if (ImGui.Button(FontAwesomeIcon.User.ToIconString(), buttonSize))
                {
                    TabSelection = TabSelection == SelectedTab.Individual ? SelectedTab.None : SelectedTab.Individual;
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }
                ImGui.SameLine();
                var xAfter = ImGui.GetCursorScreenPos();
                if (TabSelection == SelectedTab.Individual)
                    drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
                        xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
                        underlineColor, 2);
            }
            UiSharedService.AttachToolTip("Individual Pair Menu");

            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                var x = ImGui.GetCursorScreenPos();
                if (ImGui.Button(FontAwesomeIcon.Users.ToIconString(), buttonSize))
                {
                    TabSelection = TabSelection == SelectedTab.Syncshell ? SelectedTab.None : SelectedTab.Syncshell;
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }
                ImGui.SameLine();
                var xAfter = ImGui.GetCursorScreenPos();
                if (TabSelection == SelectedTab.Syncshell)
                    drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
                        xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
                        underlineColor, 2);
            }
            UiSharedService.AttachToolTip("Syncshell Menu");

            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                if (ImGui.Button(FontAwesomeIcon.Comments.ToIconString(), buttonSize))
                {
                    _lightlessMediator.Publish(new UiToggleMessage(typeof(ZoneChatUi)));
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }
            }
            UiSharedService.AttachToolTip("Lightless Chat");
            ImGui.SameLine();

            ImGui.SameLine();
            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                var x = ImGui.GetCursorScreenPos();
                if (ImGui.Button(FontAwesomeIcon.Compass.ToIconString(), buttonSize))
                {
                    TabSelection = TabSelection == SelectedTab.Lightfinder ? SelectedTab.None : SelectedTab.Lightfinder;
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }

                ImGui.SameLine();
                var xAfter = ImGui.GetCursorScreenPos();
                if (TabSelection == SelectedTab.Lightfinder)
                    drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
                        xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
                        underlineColor, 2);
            }
            UiSharedService.AttachToolTip("Lightfinder");

            ImGui.SameLine();
            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                var x = ImGui.GetCursorScreenPos();
                if (ImGui.Button(FontAwesomeIcon.UserCog.ToIconString(), buttonSize))
                {
                    TabSelection = TabSelection == SelectedTab.UserConfig ? SelectedTab.None : SelectedTab.UserConfig;
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }

                ImGui.SameLine();
                var xAfter = ImGui.GetCursorScreenPos();
                if (TabSelection == SelectedTab.UserConfig)
                    drawList.AddLine(x with { Y = x.Y + buttonSize.Y + spacing.Y },
                        xAfter with { Y = xAfter.Y + buttonSize.Y + spacing.Y, X = xAfter.X - spacing.X },
                        underlineColor, 2);
            }
            UiSharedService.AttachToolTip("Your User Menu");

            ImGui.SameLine();
            using (ImRaii.PushFont(UiBuilder.IconFont))
            {
                var x = ImGui.GetCursorScreenPos();
                if (ImGui.Button(FontAwesomeIcon.Cog.ToIconString(), buttonSize))
                {
                    _lightlessMediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
                }
                if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
                {
                    Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, buttonBorderThickness, exactSize: true, clipToElement: true, roundingOverride: buttonRounding);
                }
                ImGui.SameLine();
            }
            UiSharedService.AttachToolTip("Open Lightless Settings");

            ImGui.NewLine();
            btncolor.Dispose();

            ImGuiHelpers.ScaledDummy(spacing);

            if (TabSelection == SelectedTab.Individual)
            {
                DrawAddPair(availableWidth, spacing.X);
                DrawGlobalIndividualButtons(availableWidth, spacing.X);
            }
            else if (TabSelection == SelectedTab.Syncshell)
            {
                DrawSyncshellMenu(availableWidth, spacing.X);
                DrawGlobalSyncshellButtons(availableWidth, spacing.X);
            }
            else if (TabSelection == SelectedTab.Lightfinder)
            {
                DrawLightfinderMenu(availableWidth, spacing.X);
            }
            else if (TabSelection == SelectedTab.UserConfig)
            {
                DrawUserConfig(availableWidth, spacing.X);
            }

            if (TabSelection != SelectedTab.None) ImGuiHelpers.ScaledDummy(3f);


            DrawIncomingPairRequests(availableWidth);

            ImGui.Separator();

            DrawFilter(availableWidth, spacing.X);
        }
        finally
        {
            _currentSnapshot = null;
        }
    }

    private void DrawAddPair(float availableXWidth, float spacingX)
    {
        var buttonSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.UserPlus, "Add");
        ImGui.SetNextItemWidth(availableXWidth - buttonSize - spacingX);
        ImGui.InputTextWithHint("##otheruid", "Other players UID/Alias", ref _pairToAdd, 20);
        ImGui.SameLine();
        var alreadyExisting = Snapshot.DirectPairs.Any(p => string.Equals(p.UserData.UID, _pairToAdd, StringComparison.Ordinal) || string.Equals(p.UserData.Alias, _pairToAdd, StringComparison.Ordinal));
        using (ImRaii.Disabled(alreadyExisting || string.IsNullOrEmpty(_pairToAdd)))
        {
            if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserPlus, "Add"))
            {
                _ = _apiController.UserAddPair(new(new(_pairToAdd)));
                _pairToAdd = string.Empty;
            }
        }
        UiSharedService.AttachToolTip("Pair with " + (_pairToAdd.IsNullOrEmpty() ? "other user" : _pairToAdd));
    }

    private void DrawIncomingPairRequests(float availableWidth)
    {
        var requests = _pairRequestService.GetActiveRequests();
        var count = requests.Count;
        if (count == 0)
        {
            _pairRequestsExpanded = false;
            _lastRequestCount = 0;
            return;
        }

        if (count > _lastRequestCount)
        {
            _pairRequestsExpanded = true;
        }
        _lastRequestCount = count;

        var label = $"Incoming Pair Requests - {count}##IncomingPairRequestsHeader";

        using (ImRaii.PushColor(ImGuiCol.Header, UIColors.Get("LightlessPurple")))
        using (ImRaii.PushColor(ImGuiCol.HeaderHovered, UIColors.Get("LightlessPurpleActive")))
        using (ImRaii.PushColor(ImGuiCol.HeaderActive, UIColors.Get("LightlessPurple")))
        {
            bool open = ImGui.CollapsingHeader(label, ImGuiTreeNodeFlags.DefaultOpen);
            _pairRequestsExpanded = open;

            if (ImGui.IsItemHovered())
                UiSharedService.AttachToolTip("Expand to view incoming pair requests.");

            if (open)
            {
                var lineHeight = ImGui.GetTextLineHeightWithSpacing();
                //var desiredHeight = Math.Clamp(count * lineHeight * 2f, 130f * ImGuiHelpers.GlobalScale, 185f * ImGuiHelpers.GlobalScale); we use resize bar instead

                ImGui.SetCursorPosX(ImGui.GetCursorPosX() - 2f);

                using (ImRaii.PushColor(ImGuiCol.ChildBg, UIColors.Get("LightlessPurple")))
                using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 6f))
                {
                    if (ImGui.BeginChild("##IncomingPairRequestsOuter", new Vector2(availableWidth + 5f, _pairRequestsHeight), true))
                    {
                        var defaultChildBg = ImGui.GetStyle().Colors[(int)ImGuiCol.WindowBg];
                        using (ImRaii.PushColor(ImGuiCol.ChildBg, defaultChildBg))
                        using (ImRaii.PushStyle(ImGuiStyleVar.ChildRounding, 5f))
                        using (ImRaii.PushStyle(ImGuiStyleVar.WindowPadding, new Vector2(6, 6)))
                        {
                            if (ImGui.BeginChild("##IncomingPairRequestsInner", new Vector2(0, 0), true))
                            {
                                using (ImRaii.PushColor(ImGuiCol.TableBorderStrong, ImGui.GetStyle().Colors[(int)ImGuiCol.Border]))
                                using (ImRaii.PushColor(ImGuiCol.TableBorderLight, ImGui.GetStyle().Colors[(int)ImGuiCol.Border]))
                                {
                                    DrawPairRequestList(requests);
                                }
                            }
                            ImGui.EndChild();
                        }
                    }
                    ImGui.EndChild();

                    ImGui.PushStyleColor(ImGuiCol.Button, UIColors.Get("ButtonDefault"));
                    ImGui.PushStyleColor(ImGuiCol.ButtonHovered, UIColors.Get("LightlessPurple"));
                    ImGui.PushStyleColor(ImGuiCol.ButtonActive, UIColors.Get("LightlessPurpleActive"));
                    ImGui.Button("##resizeHandle", new Vector2(availableWidth, 4f));
                    ImGui.PopStyleColor(3);

                    if (ImGui.IsItemActive())
                    {
                        _pairRequestsHeight += ImGui.GetIO().MouseDelta.Y;
                        _pairRequestsHeight = Math.Clamp(_pairRequestsHeight, 100f, 300f);
                    }
                }
            }
        }
    }

    private void DrawPairRequestList(IReadOnlyList<PairRequestService.PairRequestDisplay> requests)
    {
        float playerColWidth = 207f * ImGuiHelpers.GlobalScale;
        float receivedColWidth = 73f * ImGuiHelpers.GlobalScale;
        float actionsColWidth = 50f * ImGuiHelpers.GlobalScale;

        ImGui.Separator();
        ImGui.TextUnformatted("Player");
        ImGui.SameLine(playerColWidth + 2f);
        ImGui.TextUnformatted("Received");
        ImGui.SameLine(playerColWidth + receivedColWidth + 12f);
        ImGui.TextUnformatted("Actions");
        ImGui.Separator();

        foreach (var request in requests)
        {
            ImGui.BeginGroup();

            var label = string.IsNullOrEmpty(request.DisplayName) ? request.HashedCid : request.DisplayName;

            ImGui.TextUnformatted(label.Truncate(26));
            if (ImGui.IsItemHovered())
            {
                ImGui.BeginTooltip();
                ImGui.TextUnformatted(label);
                ImGui.EndTooltip();
            }

            ImGui.SameLine(playerColWidth);

            ImGui.TextUnformatted(GetRelativeTime(request.ReceivedAt));
            ImGui.SameLine(playerColWidth + receivedColWidth);

            DrawPairRequestActions(request);

            ImGui.EndGroup();
        }
    }

    private void DrawPairRequestActions(PairRequestService.PairRequestDisplay request)
    {
        using var id = ImRaii.PushId(request.HashedCid);
        var label = string.IsNullOrEmpty(request.DisplayName) ? request.HashedCid : request.DisplayName;
        var inFlight = _pendingPairRequestActions.Contains(request.HashedCid);
        using (ImRaii.Disabled(inFlight))
        {
            if (_uiSharedService.IconButton(FontAwesomeIcon.Check))
            {
                _ = AcceptPairRequestAsync(request);
            }
            if (ImGui.IsItemHovered())
                ImGui.SetTooltip("Accept request");

            ImGui.SameLine();

            if (_uiSharedService.IconButton(FontAwesomeIcon.Times))
            {
                RejectPairRequest(request.HashedCid, label);
            }
            if (ImGui.IsItemHovered())
                ImGui.SetTooltip("Decline request");
        }
    }

    private static string GetRelativeTime(DateTime receivedAt)
    {
        var delta = DateTime.UtcNow - receivedAt;
        if (delta <= TimeSpan.FromSeconds(10))
        {
            return "Just now";
        }

        if (delta.TotalMinutes >= 1)
        {
            return $"{Math.Floor(delta.TotalMinutes)}m {delta.Seconds:D2}s ago";
        }

        return $"{delta.Seconds}s ago";
    }

    private async Task AcceptPairRequestAsync(PairRequestService.PairRequestDisplay request)
    {
        if (!_pendingPairRequestActions.Add(request.HashedCid))
        {
            return;
        }

        try
        {
            var myCidHash = _dalamudUtilService.GetCID().ToString().GetHash256();
            await _apiController.TryPairWithContentId(request.HashedCid).ConfigureAwait(false);
            _pairRequestService.RemoveRequest(request.HashedCid);

            var display = string.IsNullOrEmpty(request.DisplayName) ? request.HashedCid : request.DisplayName;
            _lightlessMediator.Publish(new NotificationMessage(
                "Pair request accepted",
                $"Sent a pair request back to {display}.",
                NotificationType.Info,
                TimeSpan.FromSeconds(3)));
        }
        catch (Exception ex)
        {
            _lightlessMediator.Publish(new NotificationMessage(
                "Failed to accept pair request",
                ex.Message,
                NotificationType.Error,
                TimeSpan.FromSeconds(5)));
        }
        finally
        {
            _pendingPairRequestActions.Remove(request.HashedCid);
        }
    }

    private void RejectPairRequest(string hashedCid, string playerName)
    {
        if (!_pairRequestService.RemoveRequest(hashedCid))
        {
            return;
        }

        _lightlessMediator.Publish(new NotificationMessage("Pair request declined", "Declined " + playerName + "'s pending pair request.",
            NotificationType.Info,
            TimeSpan.FromSeconds(3)));
    }

    private void DrawFilter(float availableWidth, float spacingX)
    {
        var buttonSize = _uiSharedService.GetIconTextButtonSize(FontAwesomeIcon.Ban, "Clear");
        ImGui.SetNextItemWidth(availableWidth - buttonSize - spacingX);
        string filter = Filter;
        if (ImGui.InputTextWithHint("##filter", "Filter for UID/notes", ref filter, 255))
        {
            Filter = filter;
        }
        if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenBlockedByActiveItem) || ImGui.IsItemActive())
        {
            Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, 10, exactSize: true, clipToElement: true, roundingOverride: ImGui.GetStyle().FrameRounding);
        }
        ImGui.SameLine();
        var disableClear = string.IsNullOrEmpty(Filter);
        using var disabled = ImRaii.Disabled(disableClear);
        var clearHovered = false;
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.Ban, "Clear"))
        {
            Filter = string.Empty;
        }
        clearHovered = ImGui.IsItemHovered();
        if (!disableClear && clearHovered)
        {
            Selune.RegisterHighlight(ImGui.GetItemRectMin(), ImGui.GetItemRectMax(), SeluneHighlightMode.Both, true, 10, exactSize: true, clipToElement: true, roundingOverride: ImGui.GetStyle().FrameRounding);
        }
    }

    private void DrawGlobalIndividualButtons(float availableXWidth, float spacingX)
    {
        var buttonX = (availableXWidth - (spacingX * 3)) / 4f;
        var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y;
        var buttonSize = new Vector2(buttonX, buttonY);

        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Pause.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Individual Pause");
            }
        }
        UiSharedService.AttachToolTip("Globally resume or pause all individual pairs." + UiSharedService.TooltipSeparator
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.VolumeUp.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Individual Sounds");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable sound sync with all individual pairs."
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Running.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Individual Animations");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable animation sync with all individual pairs." + UiSharedService.TooltipSeparator
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Sun.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Individual VFX");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable VFX sync with all individual pairs." + UiSharedService.TooltipSeparator
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));


        PopupIndividualSetting("Individual Pause", "Unpause all individuals", "Pause all individuals",
            FontAwesomeIcon.Play, FontAwesomeIcon.Pause,
            (perm) =>
            {
                perm.SetPaused(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetPaused(true);
                return perm;
            });
        PopupIndividualSetting("Individual Sounds", "Enable sounds for all individuals", "Disable sounds for all individuals",
            FontAwesomeIcon.VolumeUp, FontAwesomeIcon.VolumeMute,
            (perm) =>
            {
                perm.SetDisableSounds(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableSounds(true);
                return perm;
            });
        PopupIndividualSetting("Individual Animations", "Enable animations for all individuals", "Disable animations for all individuals",
            FontAwesomeIcon.Running, FontAwesomeIcon.Stop,
            (perm) =>
            {
                perm.SetDisableAnimations(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableAnimations(true);
                return perm;
            });
        PopupIndividualSetting("Individual VFX", "Enable VFX for all individuals", "Disable VFX for all individuals",
            FontAwesomeIcon.Sun, FontAwesomeIcon.Circle,
            (perm) =>
            {
                perm.SetDisableVFX(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableVFX(true);
                return perm;
            });
    }

    private void DrawGlobalSyncshellButtons(float availableXWidth, float spacingX)
    {
        var buttonX = (availableXWidth - (spacingX * 4)) / 5f;
        var buttonY = _uiSharedService.GetIconButtonSize(FontAwesomeIcon.Pause).Y;
        var buttonSize = new Vector2(buttonX, buttonY);

        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Pause.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Syncshell Pause");
            }
        }
        UiSharedService.AttachToolTip("Globally resume or pause all syncshells." + UiSharedService.TooltipSeparator
                        + "Note: This will not affect users with preferred permissions in syncshells."
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.VolumeUp.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Syncshell Sounds");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable sound sync with all syncshells." + UiSharedService.TooltipSeparator
                        + "Note: This will not affect users with preferred permissions in syncshells."
                        + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Running.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Syncshell Animations");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable animation sync with all syncshells." + UiSharedService.TooltipSeparator
                        + "Note: This will not affect users with preferred permissions in syncshells."
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0);

            if (ImGui.Button(FontAwesomeIcon.Sun.ToIconString(), buttonSize))
            {
                ImGui.OpenPopup("Syncshell VFX");
            }
        }
        UiSharedService.AttachToolTip("Globally enable or disable VFX sync with all syncshells." + UiSharedService.TooltipSeparator
                        + "Note: This will not affect users with preferred permissions in syncshells."
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));


        PopupSyncshellSetting("Syncshell Pause", "Unpause all syncshells", "Pause all syncshells",
            FontAwesomeIcon.Play, FontAwesomeIcon.Pause,
            (perm) =>
            {
                perm.SetPaused(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetPaused(true);
                return perm;
            });
        PopupSyncshellSetting("Syncshell Sounds", "Enable sounds for all syncshells", "Disable sounds for all syncshells",
            FontAwesomeIcon.VolumeUp, FontAwesomeIcon.VolumeMute,
            (perm) =>
            {
                perm.SetDisableSounds(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableSounds(true);
                return perm;
            });
        PopupSyncshellSetting("Syncshell Animations", "Enable animations for all syncshells", "Disable animations for all syncshells",
            FontAwesomeIcon.Running, FontAwesomeIcon.Stop,
            (perm) =>
            {
                perm.SetDisableAnimations(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableAnimations(true);
                return perm;
            });
        PopupSyncshellSetting("Syncshell VFX", "Enable VFX for all syncshells", "Disable VFX for all syncshells",
            FontAwesomeIcon.Sun, FontAwesomeIcon.Circle,
            (perm) =>
            {
                perm.SetDisableVFX(false);
                return perm;
            },
            (perm) =>
            {
                perm.SetDisableVFX(true);
                return perm;
            });

        ImGui.SameLine();
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            using var disabled = ImRaii.Disabled(_globalControlCountdown > 0 || !UiSharedService.CtrlPressed());

            if (ImGui.Button(FontAwesomeIcon.Check.ToIconString(), buttonSize))
            {
                _ = GlobalControlCountdown(10);
                var bulkSyncshells = Snapshot.GroupPairs.Keys.OrderBy(g => g.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)
                    .ToDictionary(g => g.Group.GID, g =>
                    {
                        var perm = g.GroupUserPermissions;
                        perm.SetDisableSounds(g.GroupPermissions.IsPreferDisableSounds());
                        perm.SetDisableAnimations(g.GroupPermissions.IsPreferDisableAnimations());
                        perm.SetDisableVFX(g.GroupPermissions.IsPreferDisableVFX());
                        return perm;
                    }, StringComparer.Ordinal);

                _ = _apiController.SetBulkPermissions(new(new(StringComparer.Ordinal), bulkSyncshells)).ConfigureAwait(false);
            }
        }
        UiSharedService.AttachToolTip("Globally align syncshell permissions to suggested syncshell permissions." + UiSharedService.TooltipSeparator
            + "Note: This will not affect users with preferred permissions in syncshells." + Environment.NewLine
            + "Note: If multiple users share one syncshell the permissions to that user will be set to " + Environment.NewLine
            + "the ones of the last applied syncshell in alphabetical order." + UiSharedService.TooltipSeparator
            + "Hold CTRL to enable this button"
            + (_globalControlCountdown > 0 ? UiSharedService.TooltipSeparator + "Available again in " + _globalControlCountdown + " seconds." : string.Empty));
    }

    private void DrawSyncshellMenu(float availableWidth, float spacingX)
    {
        var buttonX = (availableWidth - (spacingX)) / 2f;

        using (ImRaii.Disabled(Snapshot.GroupPairs.Keys
            .Distinct()
            .Count(g => string.Equals(g.OwnerUID, _apiController.UID, StringComparison.Ordinal)) >= _apiController.ServerInfo.MaxGroupsCreatedByUser))
        {
            if (_uiSharedService.IconTextButton(FontAwesomeIcon.Plus, "Create new Syncshell", buttonX))
            {
                _lightlessMediator.Publish(new UiToggleMessage(typeof(CreateSyncshellUI)));
            }
            ImGui.SameLine();
        }

        using (ImRaii.Disabled(Snapshot.GroupPairs.Keys.Distinct().Count() >= _apiController.ServerInfo.MaxGroupsJoinedByUser))
        {
            if (_uiSharedService.IconTextButton(FontAwesomeIcon.Users, "Join existing Syncshell", buttonX))
            {
                _lightlessMediator.Publish(new UiToggleMessage(typeof(JoinSyncshellUI)));
            }
        }
    }

    private void DrawLightfinderMenu(float availableWidth, float spacingX)
    {
        var buttonX = (availableWidth - (spacingX)) / 2f;

        var lightFinderLabel = GetLightfinderFinderLabel();
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCirclePlus, lightFinderLabel, buttonX, center: true))
        {
            _lightlessMediator.Publish(new UiToggleMessage(typeof(LightFinderUI)));
        }

        ImGui.SameLine();

        var syncshellFinderLabel = GetSyncshellFinderLabel();
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.Globe, syncshellFinderLabel, buttonX, center: true))
        {
            _lightlessMediator.Publish(new UiToggleMessage(typeof(SyncshellFinderUI)));
        }
    }

    private string GetLightfinderFinderLabel()
    {
        string label = "Lightfinder";

        if (_lightFinderService.IsBroadcasting)
        {
            var hashExclude = _dalamudUtilService.GetCID().ToString().GetHash256();
            var nearbyCount = _lightFinderScannerService.GetActiveBroadcasts(hashExclude).Count;
            return $"{label} ({nearbyCount})";
        }    

        return label;
    }

    private string GetSyncshellFinderLabel()
    {
        if (!_lightFinderService.IsBroadcasting)
            return "Syncshell Finder";

        var nearbyCount = _lightFinderScannerService
            .GetActiveSyncshellBroadcasts(excludeLocal: true)
            .Where(b => !string.IsNullOrEmpty(b.GID))
            .Select(b => b.GID!)
            .Distinct(StringComparer.Ordinal)
            .Count();

        return nearbyCount > 0 ? $"Syncshell Finder ({nearbyCount})" : "Syncshell Finder";
    }

    private void DrawUserConfig(float availableWidth, float spacingX)
    {
        var buttonX = (availableWidth - spacingX) / 2f;
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.UserCircle, "Edit Lightless Profile", buttonX))
        {
            _lightlessMediator.Publish(new UiToggleMessage(typeof(EditProfileUi)));
        }
        UiSharedService.AttachToolTip("Edit your Lightless Profile");
        ImGui.SameLine();
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.PersonCircleQuestion, "Chara Data Analysis", buttonX))
        {
            _lightlessMediator.Publish(new UiToggleMessage(typeof(DataAnalysisUi)));
        }
        UiSharedService.AttachToolTip("View and analyze your generated character data");
        if (_uiSharedService.IconTextButton(FontAwesomeIcon.Running, "Character Data Hub", availableWidth))
        {
            _lightlessMediator.Publish(new UiToggleMessage(typeof(CharaDataHubUi)));
        }
    }

    private async Task GlobalControlCountdown(int countdown)
    {
#if DEBUG
        return;
#endif

        _globalControlCountdown = countdown;
        while (_globalControlCountdown > 0)
        {
            await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
            _globalControlCountdown--;
        }
    }

    private void PopupIndividualSetting(string popupTitle, string enableText, string disableText,
                    FontAwesomeIcon enableIcon, FontAwesomeIcon disableIcon,
        Func<UserPermissions, UserPermissions> actEnable, Func<UserPermissions, UserPermissions> actDisable)
    {
        if (ImGui.BeginPopup(popupTitle))
        {
            if (_uiSharedService.IconTextButton(enableIcon, enableText, null, true))
            {
                _ = GlobalControlCountdown(10);
                var bulkIndividualPairs = Snapshot.PairsWithGroups.Keys
                    .Where(g => g.IndividualPairStatus == IndividualPairStatus.Bidirectional)
                    .ToDictionary(g => g.UserPair.User.UID, g =>
                    {
                        return actEnable(g.UserPair.OwnPermissions);
                    }, StringComparer.Ordinal);

                _ = _apiController.SetBulkPermissions(new(bulkIndividualPairs, new(StringComparer.Ordinal))).ConfigureAwait(false);
                ImGui.CloseCurrentPopup();
            }

            if (_uiSharedService.IconTextButton(disableIcon, disableText, null, true))
            {
                _ = GlobalControlCountdown(10);
                var bulkIndividualPairs = Snapshot.PairsWithGroups.Keys
                    .Where(g => g.IndividualPairStatus == IndividualPairStatus.Bidirectional)
                    .ToDictionary(g => g.UserPair.User.UID, g =>
                    {
                        return actDisable(g.UserPair.OwnPermissions);
                    }, StringComparer.Ordinal);

                _ = _apiController.SetBulkPermissions(new(bulkIndividualPairs, new(StringComparer.Ordinal))).ConfigureAwait(false);
                ImGui.CloseCurrentPopup();
            }
            ImGui.EndPopup();
        }
    }
    private void PopupSyncshellSetting(string popupTitle, string enableText, string disableText,
        FontAwesomeIcon enableIcon, FontAwesomeIcon disableIcon,
        Func<GroupUserPreferredPermissions, GroupUserPreferredPermissions> actEnable,
        Func<GroupUserPreferredPermissions, GroupUserPreferredPermissions> actDisable)
    {
        if (ImGui.BeginPopup(popupTitle))
        {

            if (_uiSharedService.IconTextButton(enableIcon, enableText, null, true))
            {
                _ = GlobalControlCountdown(10);
                var bulkSyncshells = Snapshot.GroupPairs.Keys
                    .OrderBy(u => u.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)
                    .ToDictionary(g => g.Group.GID, g =>
                    {
                        return actEnable(g.GroupUserPermissions);
                    }, StringComparer.Ordinal);

                _ = _apiController.SetBulkPermissions(new(new(StringComparer.Ordinal), bulkSyncshells)).ConfigureAwait(false);
                ImGui.CloseCurrentPopup();
            }

            if (_uiSharedService.IconTextButton(disableIcon, disableText, null, true))
            {
                _ = GlobalControlCountdown(10);
                var bulkSyncshells = Snapshot.GroupPairs.Keys
                    .OrderBy(u => u.GroupAliasOrGID, StringComparer.OrdinalIgnoreCase)
                    .ToDictionary(g => g.Group.GID, g =>
                    {
                        return actDisable(g.GroupUserPermissions);
                    }, StringComparer.Ordinal);

                _ = _apiController.SetBulkPermissions(new(new(StringComparer.Ordinal), bulkSyncshells)).ConfigureAwait(false);
                ImGui.CloseCurrentPopup();
            }
            ImGui.EndPopup();
        }
    }
}