using Dalamud.Interface;
using Dalamud.Interface.ImGuiFileDialog;
using Dalamud.Interface.Windowing;
using LightlessSync.LightlessConfiguration;
using LightlessSync.PlayerData.Factories;
using LightlessSync.Services.Mediator;
using LightlessSync.UI;
using LightlessSync.UI.Style;
using Microsoft.Extensions.Logging;

namespace LightlessSync.Services;

public sealed class UiService : DisposableMediatorSubscriberBase
{
    private readonly List<WindowMediatorSubscriberBase> _createdWindows = [];
    private readonly IUiBuilder _uiBuilder;
    private readonly FileDialogManager _fileDialogManager;
    private readonly ILogger<UiService> _logger;
    private readonly LightlessConfigService _lightlessConfigService;
    private readonly WindowSystem _windowSystem;
    private readonly UiFactory _uiFactory;
    private readonly PairFactory _pairFactory;

    public UiService(ILogger<UiService> logger, IUiBuilder uiBuilder,
        LightlessConfigService lightlessConfigService, WindowSystem windowSystem,
        IEnumerable<WindowMediatorSubscriberBase> windows,
        UiFactory uiFactory, FileDialogManager fileDialogManager,
        LightlessMediator lightlessMediator, PairFactory pairFactory) : base(logger, lightlessMediator)
    {
        _logger = logger;
        _logger.LogTrace("Creating {type}", GetType().Name);
        _uiBuilder = uiBuilder;
        _lightlessConfigService = lightlessConfigService;
        _windowSystem = windowSystem;
        _uiFactory = uiFactory;
        _pairFactory = pairFactory;
        _fileDialogManager = fileDialogManager;

        _uiBuilder.DisableGposeUiHide = true;
        _uiBuilder.Draw += Draw;
        _uiBuilder.OpenConfigUi += ToggleUi;
        _uiBuilder.OpenMainUi += ToggleMainUi;

        foreach (var window in windows)
        {
            _windowSystem.AddWindow(window);
        }

        Mediator.Subscribe<ProfileOpenStandaloneMessage>(this, (msg) =>
        {
            var resolvedPair = _pairFactory.Create(msg.Pair.UniqueIdent) ?? msg.Pair;
            if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui
                && ui.Pair != null
                && ui.Pair.UniqueIdent == resolvedPair.UniqueIdent))
            {
                var window = _uiFactory.CreateStandaloneProfileUi(resolvedPair);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<GroupProfileOpenStandaloneMessage>(this, msg =>
        {
            var existingWindow = _createdWindows.Find(p => p is StandaloneProfileUi ui
                && ui.IsGroupProfile
                && ui.ProfileGroupData is not null
                && string.Equals(ui.ProfileGroupData.GID, msg.Group.GID, StringComparison.Ordinal));

            if (existingWindow is StandaloneProfileUi existing)
            {
                existing.IsOpen = true;
            }
            else
            {
                var window = _uiFactory.CreateStandaloneGroupProfileUi(msg.Group);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<CloseGroupProfilePreviewMessage>(this, msg =>
        {
            var window = _createdWindows.Find(p => p is StandaloneProfileUi ui
                && ui.IsGroupProfile
                && ui.ProfileGroupData is not null
                && string.Equals(ui.ProfileGroupData.GID, msg.Group.Group.GID, StringComparison.Ordinal));

            if (window is not null)
            {
                _windowSystem.RemoveWindow(window);
                _createdWindows.Remove(window);
                window.Dispose();
            }
        });

        Mediator.Subscribe<OpenSelfProfilePreviewMessage>(this, msg =>
        {
            if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui
                && ui.Pair is null
                && !ui.IsGroupProfile
                && !ui.IsLightfinderContext
                && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal)))
            {
                var window = _uiFactory.CreateStandaloneProfileUi(msg.User);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<CloseSelfProfilePreviewMessage>(this, msg =>
        {
            var window = _createdWindows.Find(p => p is StandaloneProfileUi ui
                && ui.Pair is null
                && !ui.IsGroupProfile
                && !ui.IsLightfinderContext
                && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal));

            if (window is not null)
            {
                _windowSystem.RemoveWindow(window);
                _createdWindows.Remove(window);
                window.Dispose();
            }
        });

        Mediator.Subscribe<OpenLightfinderProfileMessage>(this, msg =>
        {
            if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui && ui.IsLightfinderContext && string.Equals(ui.LightfinderCid, msg.HashedCid, StringComparison.Ordinal)))
            {
                var window = _uiFactory.CreateLightfinderProfileUi(msg.User, msg.HashedCid);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<OpenUserProfileMessage>(this, msg =>
        {
            if (!_createdWindows.Exists(p => p is StandaloneProfileUi ui
                && !ui.IsLightfinderContext
                && !ui.IsGroupProfile
                && ui.Pair is null
                && ui.ProfileUserData is not null
                && string.Equals(ui.ProfileUserData.UID, msg.User.UID, StringComparison.Ordinal)))
            {
                var window = _uiFactory.CreateStandaloneProfileUi(msg.User);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<OpenSyncshellAdminPanel>(this, (msg) =>
        {
            if (!_createdWindows.Exists(p => p is SyncshellAdminUI ui
                && string.Equals(ui.GroupFullInfo.GID, msg.GroupInfo.GID, StringComparison.Ordinal)))
            {
                var window = _uiFactory.CreateSyncshellAdminUi(msg.GroupInfo);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<OpenPermissionWindow>(this, (msg) =>
        {
            var resolvedPair = _pairFactory.Create(msg.Pair.UniqueIdent) ?? msg.Pair;
            if (!_createdWindows.Exists(p => p is PermissionWindowUI ui
                && ui.Pair is not null
                && ui.Pair.UniqueIdent == resolvedPair.UniqueIdent))
            {
                var window = _uiFactory.CreatePermissionPopupUi(resolvedPair);
                _createdWindows.Add(window);
                _windowSystem.AddWindow(window);
            }
        });

        Mediator.Subscribe<RemoveWindowMessage>(this, (msg) =>
        {
            _windowSystem.RemoveWindow(msg.Window);
            _createdWindows.Remove(msg.Window);
            msg.Window.Dispose();
        });
    }

    public void ToggleMainUi()
    {
        if (_lightlessConfigService.Current.HasValidSetup())
            Mediator.Publish(new UiToggleMessage(typeof(CompactUi)));
        else
            Mediator.Publish(new UiToggleMessage(typeof(IntroUi)));
    }

    public void ToggleUi()
    {
        if (_lightlessConfigService.Current.HasValidSetup())
            Mediator.Publish(new UiToggleMessage(typeof(SettingsUi)));
        else
            Mediator.Publish(new UiToggleMessage(typeof(IntroUi)));
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);

        _logger.LogTrace("Disposing {type}", GetType().Name);

        _windowSystem.RemoveAllWindows();

        foreach (var window in _createdWindows)
        {
            window.Dispose();
        }

        _uiBuilder.Draw -= Draw;
        _uiBuilder.OpenConfigUi -= ToggleUi;
        _uiBuilder.OpenMainUi -= ToggleMainUi;
    }

    private void Draw()
    {
        MainStyle.PushStyle();
        try
        {
            _windowSystem.Draw();
            _fileDialogManager.Draw();
        }
        finally
        {
            MainStyle.PopStyle();
        }
    }
}