using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Controls;
using PolyTrader.Core.Modularity;

namespace PolyTrader.App.Avalonia.Shell
{
    /// <summary>
    /// Avalonia-Umsetzung von <see cref="IModuleUiHost"/>.
    ///
    /// <para><b>Umstellung auf die Einfenster-Shell:</b> Früher öffnete jede View ein eigenes
    /// Fenster. Jetzt gibt es genau ein Anwendungsfenster (<see cref="Views.ShellWindow"/>); eine
    /// View ist eine <see cref="UserControl"/>-Seite, die in dessen Inhaltsbereich gehängt wird.
    /// Eine Seite wird beim ersten Aufruf erzeugt und bleibt danach für die Sitzung bestehen –
    /// das entspricht dem alten „Fenster bleibt offen": Timer, Log-Abos und der Bildlaufstand
    /// überleben den Seitenwechsel.</para>
    ///
    /// <para>Der Core-Contract ist toolkit-neutral (<see cref="ModuleView.CreateView"/> liefert
    /// <see cref="object"/>) – hier wird auf <see cref="Control"/> gecastet. Ein falscher Typ ist ein
    /// Programmierfehler und soll laut scheitern, nicht still eine leere Seite erzeugen.</para>
    /// </summary>
    public sealed class AvaloniaUiHost : IModuleUiHost
    {
        /// <summary>ID der Startseite (frühere LauncherForm/LauncherWindow).</summary>
        public const string StartViewId = "core.start";

        private readonly List<ModuleView> _views = new();
        private readonly List<UnavailableView> _unavailable = new();
        private readonly Dictionary<string, Control> _pages = new();
        private Views.ShellWindow? _shell;
        private string? _activeViewId;
        private bool _shutdownDialogOpen;

        /// <summary>True, sobald das Herunterfahren über die Sicherheitsabfrage bestätigt wurde.</summary>
        public bool ShutdownConfirmed { get; private set; }

        public event Action? OpenStateChanged;

        public IReadOnlyList<ModuleView> Views => _views;

        /// <summary>ID der gerade angezeigten Seite – die Seitenleiste hebt sie hervor.</summary>
        public string? ActiveViewId => _activeViewId;

        public void RegisterView(ModuleView view) => _views.Add(view);

        /// <summary>
        /// Ein bekanntes, in dieser Sitzung aber nicht geladenes Modul. Solche Module haben keine
        /// Seite – die Seitenleiste zeigt sie trotzdem, ausgegraut und mit dem Grund als Hinweis.
        /// </summary>
        /// <param name="Reason">Warum das Modul fehlt (Lizenz, Abschaltung, fehlender API-Key …).</param>
        public sealed record UnavailableView(string Title, string? IconKey, int Order, string Reason);

        /// <summary>
        /// Meldet ein nicht geladenes Modul an. Ohne das verschwände es spurlos aus der Oberfläche –
        /// in der Mehrfenster-Fassung fiel das kaum auf, in einer Seitenleiste ist eine unerklärt
        /// leere Rubrik dagegen schlicht ein Fehler.
        /// </summary>
        public void RegisterUnavailable(UnavailableView view) => _unavailable.Add(view);

        /// <summary>Bekannte, aber nicht geladene Module (siehe <see cref="RegisterUnavailable"/>).</summary>
        public IReadOnlyList<UnavailableView> UnavailableViews => _unavailable;

        /// <summary>Setzt das Shell-Fenster – Ziel aller Seitenwechsel und Besitzer der Dialoge.</summary>
        public void SetShell(Views.ShellWindow shell) => _shell = shell;

        /// <summary>Das Shell-Fenster, oder <c>null</c> vor dessen Aufbau (z.B. im Smoke-Lauf).</summary>
        public Window? ShellWindow => _shell;

        /// <summary>
        /// Wurde die Seite in dieser Sitzung schon einmal aufgerufen? Erbt die Bedeutung des früheren
        /// „Fenster ist offen": die Seite existiert und arbeitet weiter, auch wenn gerade eine andere
        /// angezeigt wird.
        /// </summary>
        public bool IsOpen(string viewId) => _pages.ContainsKey(viewId);

        /// <summary>Zurück auf die Startseite.</summary>
        public void ActivateMain() => OpenView(StartViewId);

        public void OpenView(string viewId)
        {
            var view = _views.FirstOrDefault(v => v.Id == viewId);
            if (view != null) OpenView(view);
        }

        public void OpenView(ModuleView view)
        {
            if (!_pages.TryGetValue(view.Id, out var page))
            {
                page = (Control)view.CreateView();
                _pages[view.Id] = page;
            }

            _activeViewId = view.Id;
            _shell?.ShowPage(view.Title, page);
            OpenStateChanged?.Invoke();
        }

        /// <summary>
        /// Zeigt die Sicherheitsabfrage (Beenden-Schaltfläche 10 s gesperrt) und fährt bei Bestätigung
        /// herunter. Aus jeder Seite aufrufbar – auch aus Modul-Seiten, die die App nicht kennen.
        /// </summary>
        public async void RequestShutdown()
        {
            if (ShutdownConfirmed || _shutdownDialogOpen) return;
            _shutdownDialogOpen = true;
            try
            {
                var dlg = new Views.ShutdownConfirmWindow();
                bool confirmed = _shell != null
                    ? await dlg.ShowDialog<bool>(_shell)
                    : await dlg.ShowDialog<bool>(new Window());
                if (!confirmed) return;

                ShutdownConfirmed = true;
                if (global::Avalonia.Application.Current?.ApplicationLifetime
                    is global::Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktop)
                {
                    desktop.Shutdown();
                }
            }
            finally
            {
                _shutdownDialogOpen = false;
            }
        }
    }
}
