using System;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using TeamsISO.App.WinUI.Services;

namespace TeamsISO.App.WinUI.Views;

public sealed partial class SettingsDrawer : UserControl
{
    /// <summary>
    /// Raised when the operator clicks the close button or hits Esc. The host
    /// (MainWindow) handles the actual collapse animation since drawer
    /// hosting lives at that level — the drawer just signals intent.
    /// </summary>
    public event EventHandler? CloseRequested;

    public SettingsDrawer()
    {
        InitializeComponent();
        BuildTabStrip();
        SelectTab("Appearance");
    }

    private string _currentTab = "Appearance";

    /// <summary>Build the tab buttons imperatively so the parse doesn't
    /// trigger a SelectionChanged before the code-behind is ready.</summary>
    private void BuildTabStrip()
    {
        foreach (var (label, key) in new[]
                 {
                     ("Appearance", "Appearance"),
                     ("Routing", "Routing"),
                     ("Display", "Display"),
                     ("Control", "Control"),
                     ("Advanced", "Advanced"),
                 })
        {
            var btn = new Button
            {
                Content = label,
                Tag = key,
                Style = (Style)Application.Current.Resources["ButtonTertiary"],
            };
            btn.Click += (s, _) =>
            {
                if (s is Button b && b.Tag is string k) SelectTab(k);
            };
            TabStrip.Children.Add(btn);
        }
    }

    private void SelectTab(string key)
    {
        _currentTab = key;
        foreach (var child in TabStrip.Children)
        {
            if (child is Button b)
            {
                var isActive = (b.Tag as string) == key;
                b.Foreground = (Microsoft.UI.Xaml.Media.SolidColorBrush)Application.Current.Resources[
                    isActive ? "AccentCyanText" : "FgSecondary"];
            }
        }
        RebuildTabContent(key);
    }

    private void RebuildTabContent(string key)
    {
        TabContent.Children.Clear();
        switch (key)
        {
            case "Appearance": BuildAppearanceTab(); break;
            case "Routing": BuildRoutingTab(); break;
            case "Display": BuildDisplayTab(); break;
            case "Control": BuildControlTab(); break;
            case "Advanced": BuildAdvancedTab(); break;
        }
    }

    private void BuildRoutingTab()
    {
        TabContent.Children.Add(SettingHeader("Routing"));
        TabContent.Children.Add(SettingRow("Framerate", "30 fps", "Target framerate the engine normalizes incoming NDI feeds to."));
        TabContent.Children.Add(SettingRow("Resolution", "1920 x 1080", "Output resolution applied to every routed participant."));
        TabContent.Children.Add(SettingRow("Aspect mode", "Letterbox", "How sources whose aspect ratio doesn't match the target are framed."));
        TabContent.Children.Add(SettingRow("Audio routing", "Per-participant", "Embed each participant's audio in their own NDI source."));
        TabContent.Children.Add(SettingNote("Settings wired to the engine in a follow-up commit."));
    }

    private void BuildDisplayTab()
    {
        TabContent.Children.Add(SettingHeader("Display & participants"));
        TabContent.Children.Add(SettingRow("Hide local self", "Yes", "Filter the operator's own preview from the participants table."));
        TabContent.Children.Add(SettingRow("Auto-disable on departure", "No", "Keep routing alive when a participant goes offline."));
        TabContent.Children.Add(SettingRow("Participant sort", "Join order", "Default sort for the participants table."));
        TabContent.Children.Add(SettingRow("Minimize to tray", "No", "Keep TeamsISO running in the system tray when the window is minimized."));
        TabContent.Children.Add(SettingRow("Launch Teams on startup", "No", "Start Teams in the background when TeamsISO opens."));
        TabContent.Children.Add(SettingRow("Auto-hide Teams windows", "No", "Hide every visible Teams window after launch."));
        TabContent.Children.Add(SettingRow("Auto-record on call", "No", "Start recording every active ISO when Teams enters a call."));
    }

    private void BuildControlTab()
    {
        TabContent.Children.Add(SettingHeader("External control surface"));
        TabContent.Children.Add(SettingRow("REST + WebSocket", "127.0.0.1:9755", "HTTP control surface for Companion / Stream Deck."));
        TabContent.Children.Add(SettingRow("OSC bridge", "127.0.0.1:9000", "UDP OSC for TouchOSC / hardware surfaces."));
        TabContent.Children.Add(SettingRow("LAN reachable", "No", "Bind the REST surface to all interfaces (warning: no auth)."));
        TabContent.Children.Add(SettingNote("Control surface protocol unchanged from the WPF host. See docs/CONTROL-SURFACE.md."));
    }

    private void BuildAdvancedTab()
    {
        TabContent.Children.Add(SettingHeader("Advanced"));
        TabContent.Children.Add(SettingRow("Embed Teams window", "No", "Experimental SetParent reparent of Teams' main window."));
        TabContent.Children.Add(SettingRow("Logs", "%LOCALAPPDATA%\\TeamsISO\\Logs", "Where rolling daily Serilog files write."));
        TabContent.Children.Add(SettingRow("Recordings", "%USERPROFILE%\\Videos\\TeamsISO", "Default per-show recording directory."));
        TabContent.Children.Add(SettingRow("Diagnostic bundle", "Export", "Zip logs + config + presets for a bug report."));
    }

    private void OnCloseClick(object sender, RoutedEventArgs e) => CloseRequested?.Invoke(this, EventArgs.Empty);

    private void OnApplyClick(object sender, RoutedEventArgs e)
    {
        // Tabs already persist on change; Apply is here for affordance
        // consistency with the WPF host. Could surface a toast in the future.
        CloseRequested?.Invoke(this, EventArgs.Empty);
    }

    private void OnResetClick(object sender, RoutedEventArgs e)
    {
        // Defaults restoration plumbing follows in the view-model wiring
        // commit. For now, just clear the dirty hint.
        DirtyHint.Text = "Reset queued — apply or close to commit.";
    }


    /// <summary>
    /// Appearance tab — theme picker, accent palette peek. The theme picker
    /// is the only setting that affects the UI immediately (others apply on
    /// the engine layer once wired). Selection writes to UIPreferences and
    /// flips Window.Content.RequestedTheme synchronously.
    /// </summary>
    private void BuildAppearanceTab()
    {
        TabContent.Children.Add(SettingHeader("Appearance"));

        var themeLabel = new TextBlock
        {
            Style = (Style)Application.Current.Resources["TextBody"],
            Text = "Theme",
            Margin = new Thickness(0, 0, 0, 6),
        };
        TabContent.Children.Add(themeLabel);

        var themeRow = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 8 };
        foreach (var (label, value) in new[]
                 {
                     ("System", "System"),
                     ("Dark", "Dark"),
                     ("Light", "Light"),
                 })
        {
            var btn = new RadioButton
            {
                Content = label,
                Tag = value,
                GroupName = "Theme",
                IsChecked = ThemeManager.Current.PreferenceMatches(value),
            };
            btn.Checked += (s, _) =>
            {
                if (s is RadioButton rb && rb.Tag is string v)
                {
                    ThemeManager.Current.Set(v);
                }
            };
            themeRow.Children.Add(btn);
        }
        TabContent.Children.Add(themeRow);

        TabContent.Children.Add(SettingNote(
            "Dark is the default for the 1:50am operator scene; light is for daytime " +
            "production. System follows the Windows app-mode preference."));

        TabContent.Children.Add(SettingDivider());
        TabContent.Children.Add(SettingHeader("Accent peek"));

        var accentRow = new StackPanel { Orientation = Orientation.Horizontal, Spacing = 12 };
        accentRow.Children.Add(AccentSwatch("Cyan", "AccentCyanSurface"));
        accentRow.Children.Add(AccentSwatch("Coral", "AccentCoral"));
        accentRow.Children.Add(AccentSwatch("Live", "StatusLive"));
        accentRow.Children.Add(AccentSwatch("Warn", "StatusWarn"));
        TabContent.Children.Add(accentRow);

        TabContent.Children.Add(SettingNote(
            "These accents work in both themes. Cyan stays bright as a surface fill " +
            "(text on top is near-black regardless of theme). For inline text use, the " +
            "light palette substitutes a darker cyan automatically."));
    }

    // ──────────────────── helpers ──────────────────────────────────────────

    private static TextBlock SettingHeader(string text) => new()
    {
        Style = (Style)Application.Current.Resources["TextHeading"],
        Text = text,
        Margin = new Thickness(0, 0, 0, 8),
    };

    private static Grid SettingRow(string label, string value, string? tooltip = null)
    {
        var g = new Grid { Margin = new Thickness(0, 0, 0, 6) };
        g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(180) });
        g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
        var l = new TextBlock
        {
            Style = (Style)Application.Current.Resources["TextBody"],
            Text = label,
            VerticalAlignment = VerticalAlignment.Center,
        };
        var v = new TextBlock
        {
            Style = (Style)Application.Current.Resources["TextSubtle"],
            Text = value,
            VerticalAlignment = VerticalAlignment.Center,
        };
        if (tooltip is not null)
        {
            ToolTipService.SetToolTip(l, tooltip);
        }
        Grid.SetColumn(l, 0);
        Grid.SetColumn(v, 1);
        g.Children.Add(l);
        g.Children.Add(v);
        return g;
    }

    private static TextBlock SettingNote(string text) => new()
    {
        Style = (Style)Application.Current.Resources["TextCaption"],
        Text = text,
        TextWrapping = TextWrapping.Wrap,
        Margin = new Thickness(0, 4, 0, 12),
    };

    private static Border SettingDivider() => new()
    {
        Height = 1,
        Background = (SolidColorBrush)Application.Current.Resources["BorderSubtle"],
        Margin = new Thickness(0, 12, 0, 12),
    };

    private static Border AccentSwatch(string label, string brushKey)
    {
        var inner = new StackPanel { Orientation = Orientation.Vertical, Spacing = 4 };
        var swatch = new Border
        {
            Width = 80,
            Height = 32,
            CornerRadius = new Microsoft.UI.Xaml.CornerRadius(6),
            Background = (SolidColorBrush)Application.Current.Resources[brushKey],
        };
        var caption = new TextBlock
        {
            Style = (Style)Application.Current.Resources["TextCaption"],
            Text = label,
            HorizontalAlignment = HorizontalAlignment.Center,
        };
        inner.Children.Add(swatch);
        inner.Children.Add(caption);
        return new Border { Child = inner };
    }
}
