using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using TeamsISO.App.WinUI.Services;
using TeamsISO.App.WinUI.ViewModels;
using Windows.Graphics;
using Windows.UI;

namespace TeamsISO.App.WinUI.Views;

public sealed partial class MainWindow : Window
{
    private MainViewModel? _viewModel;

    public MainWindow()
    {
        InitializeComponent();

        Title = "TeamsISO";

        ExtendsContentIntoTitleBar = true;
        SetTitleBar(AppTitleBar);

        AppWindow.TitleBar.ButtonBackgroundColor = Colors.Transparent;
        AppWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
        AppWindow.TitleBar.ButtonHoverForegroundColor = Colors.White;

        AppWindow.Resize(new SizeInt32(1280, 780));

        ThemeManager.Current.Themed += (_, theme) => ApplyResolvedTheme(theme);
        ApplyResolvedTheme(ThemeManager.Current.ResolveTheme());

        WireKeyboardShortcuts();
    }

    /// <summary>
    /// Attaches the window-scoped keyboard accelerators that match the
    /// WPF host's KeyBindings: F1 help, Ctrl+M marker, Ctrl+Shift+S
    /// panic stop, Ctrl+R refresh, 1-9 + NumPad 1-9 toggle ISO by visible
    /// row index. WinUI 3 KeyboardAccelerators live on UIElement, so we
    /// attach them to the content root.
    /// </summary>
    private void WireKeyboardShortcuts()
    {
        if (Content is not Microsoft.UI.Xaml.UIElement root) return;

        void Bind(Windows.System.VirtualKey key,
                  Windows.System.VirtualKeyModifiers mods,
                  Windows.Foundation.TypedEventHandler<Microsoft.UI.Xaml.Input.KeyboardAccelerator,
                                                       Microsoft.UI.Xaml.Input.KeyboardAcceleratorInvokedEventArgs> handler)
        {
            var acc = new Microsoft.UI.Xaml.Input.KeyboardAccelerator
            {
                Key = key,
                Modifiers = mods,
                ScopeOwner = root,
            };
            acc.Invoked += handler;
            root.KeyboardAccelerators.Add(acc);
        }

        // F1 — help dialog
        Bind(Windows.System.VirtualKey.F1,
             Windows.System.VirtualKeyModifiers.None,
             (s, e) => { e.Handled = true; _ = ShowHelpDialogAsync(); });

        // Ctrl+M — drop a recording marker
        Bind(Windows.System.VirtualKey.M,
             Windows.System.VirtualKeyModifiers.Control,
             (s, e) =>
             {
                 e.Handled = true;
                 if (_viewModel?.DropRecordingMarkerCommand.CanExecute(null) == true)
                     _viewModel.DropRecordingMarkerCommand.Execute(null);
             });

        // Ctrl+Shift+S — panic stop all ISOs
        Bind(Windows.System.VirtualKey.S,
             Windows.System.VirtualKeyModifiers.Control | Windows.System.VirtualKeyModifiers.Shift,
             (s, e) =>
             {
                 e.Handled = true;
                 if (_viewModel?.StopAllIsosCommand.CanExecute(null) == true)
                     _viewModel.StopAllIsosCommand.Execute(null);
             });

        // Ctrl+R — refresh NDI discovery
        Bind(Windows.System.VirtualKey.R,
             Windows.System.VirtualKeyModifiers.Control,
             (s, e) =>
             {
                 e.Handled = true;
                 if (_viewModel?.RefreshDiscoveryCommand.CanExecute(null) == true)
                     _viewModel.RefreshDiscoveryCommand.Execute(null);
             });

        // 1-9 and NumPad1-9 — toggle ISO for the Nth visible participant
        for (var i = 1; i <= 9; i++)
        {
            var idx = i.ToString();
            Bind((Windows.System.VirtualKey)(0x30 + i), // VK '1'..'9'
                 Windows.System.VirtualKeyModifiers.None,
                 (s, e) =>
                 {
                     e.Handled = true;
                     if (_viewModel?.ToggleByIndexCommand.CanExecute(idx) == true)
                         _viewModel.ToggleByIndexCommand.Execute(idx);
                 });
            Bind((Windows.System.VirtualKey)(0x60 + i), // VK NumPad1..NumPad9
                 Windows.System.VirtualKeyModifiers.None,
                 (s, e) =>
                 {
                     e.Handled = true;
                     if (_viewModel?.ToggleByIndexCommand.CanExecute(idx) == true)
                         _viewModel.ToggleByIndexCommand.Execute(idx);
                 });
        }

        // Esc — dismiss the settings drawer if open
        Bind(Windows.System.VirtualKey.Escape,
             Windows.System.VirtualKeyModifiers.None,
             (s, e) =>
             {
                 if (_drawerOpen)
                 {
                     e.Handled = true;
                     OnDrawerCloseRequested(this, System.EventArgs.Empty);
                 }
             });
    }

    private async System.Threading.Tasks.Task ShowHelpDialogAsync()
    {
        try
        {
            var dlg = new HelpDialog
            {
                XamlRoot = (Content as Microsoft.UI.Xaml.FrameworkElement)?.XamlRoot,
            };
            await dlg.ShowAsync();
        }
        catch (System.Exception ex)
        {
            StatusBarText.Text = $"Help failed: {ex.Message}";
        }
    }

    /// <summary>
    /// Hook the engine view-model in. Replaces the placeholder StackPanel
    /// inside ParticipantsHost with a live ListView. Rather than fight WinUI
    /// 3's DataTemplate compilation, we subscribe to the Participants
    /// collection and rebuild a simple StackPanel of row controls on
    /// every change. Less efficient than a virtualized ListView for huge
    /// lists, fine for the operator's ~10 max participants.
    /// </summary>
    public void AttachViewModel(MainViewModel viewModel)
    {
        _viewModel = viewModel;

        // Section header + in-call buttons → view-model commands.
        // The buttons exist in MainWindow.xaml with the matching x:Names.
        RefreshButton.Command = viewModel.RefreshDiscoveryCommand;
        EnableAllButton.Command = viewModel.EnableAllOnlineCommand;
        StopAllButton.Command = viewModel.StopAllIsosCommand;
        MarkerButton.Command = viewModel.DropRecordingMarkerCommand;

        // Status bar + participant count text refresh on VM property changes.
        ParticipantCountText.Text = viewModel.ParticipantCountText;
        StatusBarText.Text = viewModel.StatusText;
        viewModel.PropertyChanged += (_, e) =>
        {
            DispatcherQueue.TryEnqueue(() =>
            {
                switch (e.PropertyName)
                {
                    case nameof(MainViewModel.ParticipantCountText):
                        ParticipantCountText.Text = viewModel.ParticipantCountText;
                        break;
                    case nameof(MainViewModel.StatusText):
                        StatusBarText.Text = viewModel.StatusText;
                        break;
                }
            });
        };

        ParticipantsHost.Children.Clear();
        var stack = new Microsoft.UI.Xaml.Controls.StackPanel
        {
            HorizontalAlignment = HorizontalAlignment.Stretch,
            VerticalAlignment = VerticalAlignment.Top,
        };
        var scroll = new Microsoft.UI.Xaml.Controls.ScrollViewer
        {
            VerticalScrollBarVisibility = Microsoft.UI.Xaml.Controls.ScrollBarVisibility.Auto,
            Content = stack,
        };
        ParticipantsHost.Children.Add(scroll);

        void Rebuild()
        {
            stack.Children.Clear();
            foreach (var p in viewModel.Participants)
            {
                stack.Children.Add(BuildSimpleRow(p));
            }
        }

        viewModel.Participants.CollectionChanged += (_, _) =>
        {
            DispatcherQueue.TryEnqueue(Rebuild);
        };
        Rebuild();
    }

    /// <summary>
    /// Participant row — name + ISO state pill, with the cyan-accent
    /// left border when the participant is the active speaker, and the
    /// pill background flipping green/coral/amber based on ISO state.
    /// Imperative construction so we sidestep the WinUI 3 DataTemplate
    /// parser path that crashes on this build host.
    /// </summary>
    private static Microsoft.UI.Xaml.Controls.Grid BuildSimpleRow(ParticipantViewModel p)
    {
        var grid = new Microsoft.UI.Xaml.Controls.Grid
        {
            Height = 56,
            Padding = new Thickness(0, 0, 20, 0),
        };
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(3) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(20) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(1, Microsoft.UI.Xaml.GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(140) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = Microsoft.UI.Xaml.GridLength.Auto });

        // Active-speaker left accent. Visible only when IsActiveSpeaker
        // flips on (driven by MainViewModel.OnStatsTick at 1Hz).
        var accent = new Microsoft.UI.Xaml.Controls.Border
        {
            Background = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCyanText"],
            Visibility = p.IsActiveSpeaker ? Visibility.Visible : Visibility.Collapsed,
        };
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(accent, 0);
        grid.Children.Add(accent);

        var nameStack = new Microsoft.UI.Xaml.Controls.StackPanel
        {
            VerticalAlignment = VerticalAlignment.Center,
            Spacing = 2,
        };
        var nameText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.DisplayName,
            FontSize = 14,
            FontWeight = Microsoft.UI.Text.FontWeights.Medium,
        };
        var codecText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.SourceCodec,
            FontSize = 11,
            Opacity = 0.6,
        };
        nameStack.Children.Add(nameText);
        nameStack.Children.Add(codecText);
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 2);
        grid.Children.Add(nameStack);

        var outputText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.OutputName,
            FontFamily = new Microsoft.UI.Xaml.Media.FontFamily("Consolas"),
            FontSize = 12,
            VerticalAlignment = VerticalAlignment.Center,
        };
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 3);
        grid.Children.Add(outputText);

        var pillText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.IsoStateLabel,
            FontSize = 11,
            FontWeight = Microsoft.UI.Text.FontWeights.SemiBold,
            HorizontalAlignment = HorizontalAlignment.Center,
        };
        var pill = new Microsoft.UI.Xaml.Controls.Button
        {
            Command = p.ToggleIsoCommand,
            MinWidth = 80,
            Padding = new Thickness(14, 6, 14, 6),
            CornerRadius = new CornerRadius(999),
            VerticalAlignment = VerticalAlignment.Center,
            Content = pillText,
        };
        ApplyIsoPillStyling(pill, pillText, p.IsoStateLabel);
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(pill, 4);
        grid.Children.Add(pill);

        p.PropertyChanged += (_, e) =>
        {
            grid.DispatcherQueue.TryEnqueue(() =>
            {
                switch (e.PropertyName)
                {
                    case nameof(ParticipantViewModel.DisplayName):
                        nameText.Text = p.DisplayName;
                        break;
                    case nameof(ParticipantViewModel.SourceCodec):
                        codecText.Text = p.SourceCodec;
                        break;
                    case nameof(ParticipantViewModel.OutputName):
                        outputText.Text = p.OutputName;
                        break;
                    case nameof(ParticipantViewModel.IsoStateLabel):
                    case nameof(ParticipantViewModel.IsEnabled):
                        pillText.Text = p.IsoStateLabel;
                        ApplyIsoPillStyling(pill, pillText, p.IsoStateLabel);
                        break;
                    case nameof(ParticipantViewModel.IsActiveSpeaker):
                        accent.Visibility = p.IsActiveSpeaker
                            ? Visibility.Visible
                            : Visibility.Collapsed;
                        break;
                }
            });
        };

        return grid;
    }

    /// <summary>
    /// Re-color the ISO pill based on the engine's reported state.
    /// LIVE = green on green-tinted background. ERROR = coral on coral-
    /// tinted background. STARTING = amber. NO SIGNAL = amber. OFF =
    /// neutral surface. Mirrors the WPF host's IsoToggle data-trigger
    /// behavior but built imperatively from theme-resource brush keys.
    /// </summary>
    private static void ApplyIsoPillStyling(
        Microsoft.UI.Xaml.Controls.Button pill,
        Microsoft.UI.Xaml.Controls.TextBlock pillText,
        string state)
    {
        Microsoft.UI.Xaml.Media.Brush bg, border, fg;
        switch (state)
        {
            case "LIVE":
                bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLiveBg"];
                border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLive"];
                fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusLive"];
                break;
            case "ERROR":
                bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoralBg"];
                border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoral"];
                fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCoral"];
                break;
            case "NO SIGNAL":
            case "STARTING":
                bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarnBg"];
                border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarn"];
                fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["StatusWarn"];
                break;
            default: // OFF / —
                bg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BgSurface"];
                border = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BorderStrong"];
                fg = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgPrimary"];
                break;
        }
        pill.Background = bg;
        pill.BorderBrush = border;
        pill.BorderThickness = new Thickness(1);
        pillText.Foreground = fg;
    }

    /// <summary>Full rich row template — replaces BuildSimpleRow once we've verified the simple version doesn't crash.</summary>
    private static Microsoft.UI.Xaml.Controls.Grid BuildParticipantRow(ParticipantViewModel p)
    {
        var grid = new Microsoft.UI.Xaml.Controls.Grid
        {
            Height = 64,
            Padding = new Thickness(14, 0, 12, 0),
            BorderBrush = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BorderSubtle"],
            BorderThickness = new Thickness(0, 0, 0, 1),
        };
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(44) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(2, Microsoft.UI.Xaml.GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(1.4, Microsoft.UI.Xaml.GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = new Microsoft.UI.Xaml.GridLength(1.6, Microsoft.UI.Xaml.GridUnitType.Star) });
        grid.ColumnDefinitions.Add(new Microsoft.UI.Xaml.Controls.ColumnDefinition { Width = Microsoft.UI.Xaml.GridLength.Auto });

        // Avatar
        var avatar = new Microsoft.UI.Xaml.Controls.Border
        {
            Width = 36, Height = 36,
            CornerRadius = new CornerRadius(18),
            Background = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCyanMuted"],
            VerticalAlignment = VerticalAlignment.Center,
        };
        var initialsText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.Initials,
            FontSize = 13,
            FontWeight = Microsoft.UI.Text.FontWeights.SemiBold,
            Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["AccentCyanText"],
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center,
        };
        avatar.Child = initialsText;
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(avatar, 0);
        grid.Children.Add(avatar);

        // Name + codec
        var nameStack = new Microsoft.UI.Xaml.Controls.StackPanel
        {
            Margin = new Thickness(12, 0, 0, 0),
            VerticalAlignment = VerticalAlignment.Center,
            Spacing = 2,
        };
        var nameText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.DisplayName,
            FontSize = 13,
            FontWeight = Microsoft.UI.Text.FontWeights.Medium,
            Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgPrimary"],
        };
        var codecText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.SourceCodec,
            FontSize = 11,
            Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgSecondary"],
        };
        nameStack.Children.Add(nameText);
        nameStack.Children.Add(codecText);
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(nameStack, 1);
        grid.Children.Add(nameStack);

        // Audio meter
        var meter = new Microsoft.UI.Xaml.Controls.ProgressBar
        {
            Maximum = 1.0,
            Value = p.DisplayedAudioLevel,
            Height = 4,
            Margin = new Thickness(12, 0, 12, 0),
            VerticalAlignment = VerticalAlignment.Center,
        };
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(meter, 2);
        grid.Children.Add(meter);

        // Output name
        var outputText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.OutputName,
            FontFamily = new Microsoft.UI.Xaml.Media.FontFamily("Consolas"),
            FontSize = 12,
            Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgPrimary"],
            VerticalAlignment = VerticalAlignment.Center,
        };
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(outputText, 3);
        grid.Children.Add(outputText);

        // ISO toggle pill
        var pillText = new Microsoft.UI.Xaml.Controls.TextBlock
        {
            Text = p.IsoStateLabel,
            FontSize = 11,
            FontWeight = Microsoft.UI.Text.FontWeights.SemiBold,
            Foreground = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["FgPrimary"],
            HorizontalAlignment = HorizontalAlignment.Center,
        };
        var pill = new Microsoft.UI.Xaml.Controls.Button
        {
            Command = p.ToggleIsoCommand,
            MinWidth = 80,
            Padding = new Thickness(14, 6, 14, 6),
            Background = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BgSurface"],
            BorderBrush = (Microsoft.UI.Xaml.Media.Brush)Application.Current.Resources["BorderStrong"],
            BorderThickness = new Thickness(1),
            CornerRadius = new CornerRadius(999),
            VerticalAlignment = VerticalAlignment.Center,
            Content = pillText,
        };
        Microsoft.UI.Xaml.Controls.Grid.SetColumn(pill, 4);
        grid.Children.Add(pill);

        // Per-row property-change subscription — refresh text as the
        // engine pushes updates.
        p.PropertyChanged += (_, e) =>
        {
            grid.DispatcherQueue.TryEnqueue(() =>
            {
                switch (e.PropertyName)
                {
                    case nameof(ParticipantViewModel.DisplayName):
                        nameText.Text = p.DisplayName;
                        initialsText.Text = p.Initials;
                        break;
                    case nameof(ParticipantViewModel.SourceCodec):
                        codecText.Text = p.SourceCodec;
                        break;
                    case nameof(ParticipantViewModel.DisplayedAudioLevel):
                        meter.Value = p.DisplayedAudioLevel;
                        break;
                    case nameof(ParticipantViewModel.OutputName):
                        outputText.Text = p.OutputName;
                        break;
                    case nameof(ParticipantViewModel.IsoStateLabel):
                    case nameof(ParticipantViewModel.IsEnabled):
                        pillText.Text = p.IsoStateLabel;
                        break;
                }
            });
        };

        return grid;
    }

    private void OnThemeToggleClick(object sender, RoutedEventArgs e)
    {
        ThemeManager.Current.Toggle();
    }

    private bool _drawerOpen;

    private void OnSettingsClick(object sender, RoutedEventArgs e)
    {
        _drawerOpen = !_drawerOpen;
        SettingsDrawerHost.Visibility = _drawerOpen
            ? Visibility.Visible
            : Visibility.Collapsed;
        if (_drawerOpen)
        {
            SettingsDrawerHost.CloseRequested -= OnDrawerCloseRequested;
            SettingsDrawerHost.CloseRequested += OnDrawerCloseRequested;
        }
    }

    private void OnDrawerCloseRequested(object? sender, System.EventArgs e)
    {
        _drawerOpen = false;
        SettingsDrawerHost.Visibility = Visibility.Collapsed;
    }

    /// <summary>
    /// Teams orchestration — mute. Drives the Teams app's in-call mute button
    /// via UIAutomation (TeamsControlBridge does the localized-name search).
    /// Surface failures via the status bar so the operator gets feedback
    /// without a popup.
    /// </summary>
    private void OnMuteClick(object sender, RoutedEventArgs e)
    {
        var result = Services.TeamsControlBridge.ToggleMute();
        StatusBarText.Text = DescribeBridgeResult("Mute", result);
    }

    private void OnCameraClick(object sender, RoutedEventArgs e)
    {
        var result = Services.TeamsControlBridge.ToggleCamera();
        StatusBarText.Text = DescribeBridgeResult("Camera", result);
    }

    private void OnShareClick(object sender, RoutedEventArgs e)
    {
        var result = Services.TeamsControlBridge.OpenShareTray();
        StatusBarText.Text = DescribeBridgeResult("Share", result);
    }

    private void OnLeaveClick(object sender, RoutedEventArgs e)
    {
        var result = Services.TeamsControlBridge.LeaveCall();
        StatusBarText.Text = DescribeBridgeResult("Leave", result);
    }

    private static string DescribeBridgeResult(string action, Services.TeamsControlBridge.InvokeResult r) =>
        r switch
        {
            Services.TeamsControlBridge.InvokeResult.Invoked => $"{action} invoked",
            Services.TeamsControlBridge.InvokeResult.TeamsNotRunning => $"{action} failed — Teams isn't running",
            Services.TeamsControlBridge.InvokeResult.ControlNotFound => $"{action} failed — control not visible (not in a call?)",
            Services.TeamsControlBridge.InvokeResult.InvokeFailed => $"{action} failed — Teams refused the invoke",
            _ => $"{action} failed",
        };

    /// <summary>Launch Teams if not running, else show its windows.</summary>
    private void OnLaunchTeamsClick(object sender, RoutedEventArgs e)
    {
        if (Services.TeamsLauncher.IsRunning())
        {
            var shown = Services.TeamsLauncher.ShowWindows();
            StatusBarText.Text = $"Showed {shown} Teams window{(shown == 1 ? "" : "s")}";
        }
        else
        {
            if (Services.TeamsLauncher.TryLaunch(out var err))
            {
                StatusBarText.Text = "Teams launched";
            }
            else
            {
                StatusBarText.Text = $"Teams launch failed: {err}";
            }
        }
    }

    /// <summary>Toggle Teams window visibility — invisible/visible flip.</summary>
    private bool _teamsHidden;
    private void OnToggleTeamsWindowsClick(object sender, RoutedEventArgs e)
    {
        if (_teamsHidden)
        {
            var n = Services.TeamsLauncher.ShowWindows();
            _teamsHidden = false;
            StatusBarText.Text = $"Showed {n} Teams window{(n == 1 ? "" : "s")}";
        }
        else
        {
            var n = Services.TeamsLauncher.HideWindows();
            _teamsHidden = true;
            StatusBarText.Text = $"Hid {n} Teams window{(n == 1 ? "" : "s")}";
        }
    }

    private void ApplyResolvedTheme(ElementTheme theme)
    {
        if (Content is FrameworkElement root)
        {
            root.RequestedTheme = theme;
        }

        AppWindow.TitleBar.ButtonForegroundColor = ThemeManager.TitleBarForegroundFor(theme);
        AppWindow.TitleBar.ButtonHoverBackgroundColor = ThemeManager.TitleBarHoverBgFor(theme);
        AppWindow.TitleBar.ButtonPressedBackgroundColor = ThemeManager.TitleBarHoverBgFor(theme);

        ThemeToggleIcon.Glyph = theme == ElementTheme.Light ? "" : "";
    }

}
