using System;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Windows.UI;
using Windows.UI.ViewManagement;

namespace TeamsISO.App.WinUI.Services;

/// <summary>
/// Owns the active theme for the WinUI 3 host. Three preferences:
/// <c>System</c> follows the Windows app-mode setting (default for new
/// users); <c>Dark</c> and <c>Light</c> pin one regardless of the OS choice.
/// The persistence path will land alongside the existing UIPreferences in
/// the next commit — for now state lives in-process.
///
/// All public mutations push <see cref="Themed"/> to subscribers so the
/// host (MainWindow) can update the AppWindow title-bar button colors
/// (system buttons aren't part of the visual tree and need a separate
/// poke when ElementTheme changes).
/// </summary>
public sealed class ThemeManager
{
    public static ThemeManager Current { get; } = new();

    private ThemeManager()
    {
        _uiSettings = new UISettings();
        _uiSettings.ColorValuesChanged += OnSystemColorsChanged;

        // Hydrate the preference from disk so the operator's choice
        // survives across launches. Defaults to "System" if the prefs
        // file is missing or unreadable (Load() catches its own errors).
        try
        {
            var prefs = UIPreferences.Load();
            if (prefs.Theme == "System" || prefs.Theme == "Dark" || prefs.Theme == "Light")
            {
                _preference = prefs.Theme;
            }
        }
        catch
        {
            // Defensive — ThemeManager.Current is a static singleton; a
            // throw here would prevent the app from getting any theme.
        }
    }

    private readonly UISettings _uiSettings;
    private string _preference = "System";

    public string Preference => _preference;

    public event EventHandler<ElementTheme>? Themed;

    /// <summary>
    /// Resolve the preference to an absolute <see cref="ElementTheme"/>
    /// suitable for <see cref="FrameworkElement.RequestedTheme"/>.
    /// <c>System</c> resolves to the OS app-mode.
    /// </summary>
    public ElementTheme ResolveTheme() => _preference switch
    {
        "Dark" => ElementTheme.Dark,
        "Light" => ElementTheme.Light,
        _ => IsSystemDark() ? ElementTheme.Dark : ElementTheme.Light,
    };

    public bool PreferenceMatches(string value) => string.Equals(_preference, value, StringComparison.Ordinal);

    /// <summary>
    /// Cycle dark ↔ light from the title-bar toggle. If the current
    /// preference is <c>System</c>, the cycle pins to the opposite of the
    /// currently-resolved theme so the click has a visible effect.
    /// </summary>
    public ElementTheme Toggle()
    {
        var current = ResolveTheme();
        Set(current == ElementTheme.Dark ? "Light" : "Dark");
        return ResolveTheme();
    }

    /// <summary>Set the preference, persist to disk, broadcast the resolved theme.</summary>
    public void Set(string preference)
    {
        if (preference != "System" && preference != "Dark" && preference != "Light")
        {
            throw new ArgumentException("Preference must be System, Dark, or Light.", nameof(preference));
        }

        _preference = preference;
        try { UIPreferences.SetTheme(preference); }
        catch { /* persistence is best-effort */ }
        Themed?.Invoke(this, ResolveTheme());
    }

    private bool IsSystemDark()
    {
        // UISettings.GetColorValue(UIColorType.Background) returns
        // black-ish in dark mode, white-ish in light mode — the most
        // reliable cross-version check for app mode on desktop WinUI 3.
        var bg = _uiSettings.GetColorValue(UIColorType.Background);
        return ((5 * bg.G) + (2 * bg.R) + bg.B) < 8 * 128;
    }

    private void OnSystemColorsChanged(UISettings sender, object args)
    {
        // Only re-broadcast if the operator hasn't pinned a preference —
        // otherwise the explicit choice wins regardless of what the OS does.
        if (_preference == "System")
        {
            Themed?.Invoke(this, ResolveTheme());
        }
    }

    /// <summary>
    /// Compute the AppWindow title-bar foreground for the given resolved
    /// theme so the system min/max/close buttons stay readable.
    /// </summary>
    public static Color TitleBarForegroundFor(ElementTheme theme) =>
        theme == ElementTheme.Dark
            ? Color.FromArgb(0xFF, 0xF4, 0xF4, 0xF6)
            : Color.FromArgb(0xFF, 0x0A, 0x0A, 0x0A);

    public static Color TitleBarHoverBgFor(ElementTheme theme) =>
        theme == ElementTheme.Dark
            ? Color.FromArgb(0xFF, 0x33, 0x34, 0x3A)
            : Color.FromArgb(0xFF, 0xEC, 0xEE, 0xF1);
}
