using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using NexusShell.Models;
using NexusShell.Services.Diagnostics;

namespace NexusShell.Services.Workspace;

public enum WorkspaceWindowState
{
    Normal,
    Minimized,
    Closed,
}

public sealed class WorkspaceWindowDescriptor
{
    public required string AppId { get; init; }
    public required string DisplayName { get; init; }
    public required string IconKey { get; init; }
    public bool IsExternal { get; init; }
    public Window? Window { get; set; }
    public int? ProcessId { get; set; }
    public WorkspaceWindowState State { get; set; } = WorkspaceWindowState.Normal;
    public bool IsActive { get; set; }
}

public sealed class WorkspaceWindowManager
{
    private readonly DiagnosticsService _diagnostics;
    private readonly WindowEventTracker _windowTracker;
    private readonly AppLaunchTracker _launchTracker;
    private readonly ObservableCollection<WorkspaceWindowDescriptor> _activeWindows = [];
    private Window? _shellWindow;

    public WorkspaceWindowManager(
        DiagnosticsService diagnostics,
        WindowEventTracker windowTracker,
        AppLaunchTracker launchTracker)
    {
        _diagnostics = diagnostics;
        _windowTracker = windowTracker;
        _launchTracker = launchTracker;
        ActiveWindows = new ReadOnlyObservableCollection<WorkspaceWindowDescriptor>(_activeWindows);
    }

    public ReadOnlyObservableCollection<WorkspaceWindowDescriptor> ActiveWindows { get; }

    public event EventHandler? ActiveWindowsChanged;

    public void Initialize(Window shellWindow)
    {
        _shellWindow = shellWindow;
        shellWindow.Activated += (_, _) => RefreshActiveFlags(shellWindow);
    }

    public T RegisterWorkspaceWindow<T>(T window, string appId, string displayName, string iconKey = "app")
        where T : Window
    {
        if (_shellWindow is not null)
        {
            window.Owner = _shellWindow;
        }

        window.ShowInTaskbar = false;
        window.WindowStartupLocation = WindowStartupLocation.CenterOwner;

        var descriptor = new WorkspaceWindowDescriptor
        {
            AppId = appId,
            DisplayName = displayName,
            IconKey = iconKey,
            IsExternal = false,
            Window = window,
        };

        _windowTracker.Attach(window, appId, displayName);
        window.Activated += (_, _) => SetActive(descriptor);
        window.StateChanged += (_, _) => UpdateWindowState(descriptor);
        window.Closed += (_, _) => Unregister(descriptor);

        if (_activeWindows.All(w => w.AppId != appId))
        {
            _activeWindows.Add(descriptor);
        }
        else
        {
            var existing = _activeWindows.First(w => w.AppId == appId);
            existing.Window = window;
            existing.State = WorkspaceWindowState.Normal;
        }

        _launchTracker.TrackInternalLaunch(appId, displayName, true);
        _diagnostics.LogWorkspace("workspace_window_registered", displayName,
            new Dictionary<string, string> { ["appId"] = appId, ["hosting"] = "nexus-workspace" });

        NotifyChanged();
        return window;
    }

    public void RegisterExternalProcess(string appId, string displayName, Process process)
    {
        var descriptor = new WorkspaceWindowDescriptor
        {
            AppId = appId,
            DisplayName = displayName,
            IconKey = "external",
            IsExternal = true,
            ProcessId = process.Id,
            Window = null,
        };

        _activeWindows.Add(descriptor);
        _launchTracker.TrackExternalLaunch(appId, displayName, process.Id, true);
        _windowTracker.TrackExternalWindowDetected(process.ProcessName, process.Id);
        NotifyChanged();
    }

    public void Activate(string appId)
    {
        var descriptor = _activeWindows.FirstOrDefault(w => w.AppId == appId);
        if (descriptor?.Window is null)
        {
            return;
        }

        if (descriptor.State == WorkspaceWindowState.Minimized)
        {
            descriptor.Window.WindowState = WindowState.Normal;
            descriptor.State = WorkspaceWindowState.Normal;
        }

        descriptor.Window.Show();
        descriptor.Window.Activate();
        SetActive(descriptor);
        _diagnostics.LogWorkspace("workspace_window_focus", descriptor.DisplayName,
            new Dictionary<string, string> { ["appId"] = appId });
        NotifyChanged();
    }

    public void Minimize(string appId)
    {
        var descriptor = _activeWindows.FirstOrDefault(w => w.AppId == appId);
        if (descriptor?.Window is null)
        {
            return;
        }

        descriptor.Window.WindowState = WindowState.Minimized;
        descriptor.State = WorkspaceWindowState.Minimized;
        _diagnostics.LogWorkspace("workspace_window_minimize", descriptor.DisplayName,
            new Dictionary<string, string> { ["appId"] = appId });
        NotifyChanged();
    }

    public void Close(string appId)
    {
        var descriptor = _activeWindows.FirstOrDefault(w => w.AppId == appId);
        if (descriptor?.Window is null)
        {
            for (var i = _activeWindows.Count - 1; i >= 0; i--)
            {
                if (string.Equals(_activeWindows[i].AppId, appId, StringComparison.OrdinalIgnoreCase))
                {
                    _activeWindows.RemoveAt(i);
                }
            }

            NotifyChanged();
            return;
        }

        descriptor.Window.Close();
    }

    public bool IsRegistered(string appId) => _activeWindows.Any(w => w.AppId == appId && w.State != WorkspaceWindowState.Closed);

    public bool TryGetWindow(string appId, out Window? window)
    {
        var descriptor = _activeWindows.FirstOrDefault(w => w.AppId == appId);
        window = descriptor?.Window;
        return window is not null;
    }

    private void Unregister(WorkspaceWindowDescriptor descriptor)
    {
        descriptor.State = WorkspaceWindowState.Closed;
        descriptor.Window = null;
        _activeWindows.Remove(descriptor);
        _diagnostics.LogWorkspace("workspace_window_unregistered", descriptor.DisplayName,
            new Dictionary<string, string> { ["appId"] = descriptor.AppId });
        NotifyChanged();
    }

    private void SetActive(WorkspaceWindowDescriptor active)
    {
        foreach (var item in _activeWindows)
        {
            item.IsActive = ReferenceEquals(item, active);
        }

        NotifyChanged();
    }

    private void UpdateWindowState(WorkspaceWindowDescriptor descriptor)
    {
        if (descriptor.Window is null)
        {
            return;
        }

        descriptor.State = descriptor.Window.WindowState == WindowState.Minimized
            ? WorkspaceWindowState.Minimized
            : WorkspaceWindowState.Normal;

        if (descriptor.State == WorkspaceWindowState.Minimized)
        {
            descriptor.IsActive = false;
        }

        _diagnostics.LogWorkspace("workspace_window_state_changed", descriptor.DisplayName,
            new Dictionary<string, string>
            {
                ["appId"] = descriptor.AppId,
                ["state"] = descriptor.State.ToString(),
            });
        NotifyChanged();
    }

    private void RefreshActiveFlags(Window shellWindow)
    {
        foreach (var item in _activeWindows)
        {
            item.IsActive = item.Window?.IsActive == true;
        }

        if (_activeWindows.All(w => !w.IsActive))
        {
            // Shell is front-most — desktop surface active.
        }

        NotifyChanged();
    }

    private void NotifyChanged() => ActiveWindowsChanged?.Invoke(this, EventArgs.Empty);
}
