using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Shapes;
using TeamsISO.App.Services;
using TeamsISO.App.ViewModels;

namespace TeamsISO.App;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        StateChanged += OnWindowStateChanged;
        SourceInitialized += OnSourceInitialized;
        Closing += OnClosing;
    }

    public MainWindow(MainViewModel viewModel) : this()
    {
        DataContext = viewModel;
    }

    /// <summary>
    /// Restore the window's previous placement after the HWND is created (so
    /// SetWindowPos / WindowState transitions actually take effect). Falls
    /// silently back to the XAML-default startup location if no snapshot exists.
    /// </summary>
    private void OnSourceInitialized(object? sender, EventArgs e)
    {
        WindowStateStore.TryApply(this);
    }

    /// <summary>Persist the placement on close so next launch lands in the same spot.</summary>
    private void OnClosing(object? sender, System.ComponentModel.CancelEventArgs e)
    {
        WindowStateStore.Save(this);
    }

    /// <summary>Custom min button — chrome'd window has no system caption buttons.</summary>
    private void OnMinimize(object sender, RoutedEventArgs e) =>
        WindowState = WindowState.Minimized;

    /// <summary>Toggles maximize/restore. Bound to the maximize button + double-click on the drag region.</summary>
    private void OnMaximizeRestore(object sender, RoutedEventArgs e) =>
        WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;

    /// <summary>Custom close button.</summary>
    private void OnClose(object sender, RoutedEventArgs e) => Close();

    /// <summary>Opens the About dialog — version, NDI runtime, build SHA.</summary>
    private void OnAboutClick(object sender, RoutedEventArgs e)
    {
        var about = new AboutWindow { Owner = this };
        about.ShowDialog();
    }

    /// <summary>
    /// Opens the operator-presets dialog. Hands it the current participants
    /// snapshot (so Save captures live state) and the engine controller (so
    /// Apply can reconcile enable/disable). Owner is set so the chromeless
    /// dialog centers over the main window and inherits z-order.
    /// </summary>
    private void OnPresetsClick(object sender, RoutedEventArgs e)
    {
        if (DataContext is not MainViewModel vm) return;
        var dialog = new PresetsDialog(vm.Controller, vm.Participants.ToList(), vm.Toast)
        {
            Owner = this,
        };
        dialog.ShowDialog();
    }

    /// <summary>
    /// Tracks whether we have hidden Teams' windows so the next click reverses
    /// the action. We treat this as "intent" rather than a query of OS state
    /// because hidden windows still report as hidden if the operator manually
    /// re-opens them and we only care about TeamsISO's own toggle history.
    /// </summary>
    private bool _teamsWindowsHidden;

    /// <summary>
    /// Phase E.2 toggle. Hides every visible top-level Teams window on first
    /// click; shows them again on the next. Surfaces the result via the toast
    /// so the operator gets feedback even though the affected windows aren't
    /// visible anymore.
    /// </summary>
    private void OnToggleTeamsWindowClick(object sender, RoutedEventArgs e)
    {
        if (!TeamsLauncher.IsRunning())
        {
            MessageBox.Show(
                "Microsoft Teams isn't running. Click the camera icon above to launch it first.",
                "TeamsISO — Hide / show Teams",
                MessageBoxButton.OK,
                MessageBoxImage.Information);
            return;
        }

        var toast = (DataContext as MainViewModel)?.Toast;
        if (_teamsWindowsHidden)
        {
            var shown = TeamsLauncher.ShowWindows();
            _teamsWindowsHidden = false;
            toast?.Show(shown > 0 ? $"Restored {shown} Teams window(s)" : "No Teams windows to restore");
        }
        else
        {
            var hidden = TeamsLauncher.HideWindows();
            _teamsWindowsHidden = hidden > 0;
            toast?.Show(hidden > 0 ? $"Hid {hidden} Teams window(s)" : "Teams has no visible windows yet");
        }
    }

    /// <summary>
    /// Three-state click behavior matching operator intuition:
    ///   1. Teams not running → launch it via TeamsLauncher's fallback chain.
    ///   2. Teams running but its windows are hidden (we toggled them off, OR
    ///      it launched into the tray) → restore the windows + foreground them.
    ///      This is the case the previous "ask to stop" dialog was ambushing —
    ///      operators don't think of a hidden Teams as "running and ready to
    ///      stop", they think of it as "I clicked Launch and nothing happened".
    ///   3. Teams running with visible windows → bring the most recent one to
    ///      the foreground. (Stopping Teams is now a right-click action;
    ///      see OnLaunchTeamsRightClick.)
    /// </summary>
    private void OnLaunchTeamsClick(object sender, RoutedEventArgs e)
    {
        var toast = (DataContext as MainViewModel)?.Toast;

        if (!TeamsLauncher.IsRunning())
        {
            if (!TeamsLauncher.TryLaunch(out var error))
            {
                MessageBox.Show(
                    $"Could not launch Microsoft Teams.\n\n{error}",
                    "TeamsISO — Launch Teams",
                    MessageBoxButton.OK,
                    MessageBoxImage.Warning);
            }
            else
            {
                var autoHide = (DataContext as MainViewModel)?.Settings.AutoHideTeamsWindows ?? false;
                toast?.Show(autoHide
                    ? "Launching Microsoft Teams (will hide windows automatically)…"
                    : "Launching Microsoft Teams…");
                if (autoHide)
                {
                    _ = TeamsLauncher.AutoHideAfterLaunchAsync();
                    _teamsWindowsHidden = true;
                }
                else
                {
                    _teamsWindowsHidden = false;
                }
            }
            return;
        }

        // Teams is running. Always try to restore + foreground its window —
        // if windows are already visible, ShowWindows is a SetForegroundWindow
        // no-op besides bringing them forward; if they were hidden by our
        // own toggle, this is the operator's intuitive "show me Teams" path.
        var shown = TeamsLauncher.ShowWindows();
        _teamsWindowsHidden = false;
        toast?.Show(shown > 0
            ? $"Teams is already running — surfaced {shown} window(s)"
            : "Teams is running but has no visible windows yet");
    }

    /// <summary>
    /// Right-click on the rail Launch button asks to stop Teams. Split out
    /// from the left-click so a normal click is "open / surface" rather than
    /// the previous "open OR ambush you with a stop dialog".
    /// </summary>
    /// <summary>
    /// Open the experimental Teams embed window. Operator enables the
    /// preference first; this button materializes the host. See
    /// <see cref="TeamsEmbedWindow"/> for the SetParent lifecycle.
    /// </summary>
    private void OnOpenEmbedWindowClick(object sender, RoutedEventArgs e)
    {
        // Non-modal so the operator can keep using TeamsISO's controls.
        // Owner = this so it minimizes / closes with TeamsISO.
        var w = new TeamsEmbedWindow { Owner = this };
        w.Show();
    }

    private void OnLaunchTeamsRightClick(object sender, MouseButtonEventArgs e)
    {
        if (!TeamsLauncher.IsRunning()) return;

        var confirm = MessageBox.Show(
            "Microsoft Teams is currently running.\n\nClose all Teams windows now?",
            "TeamsISO — Stop Teams",
            MessageBoxButton.YesNo,
            MessageBoxImage.Question);
        if (confirm != MessageBoxResult.Yes) return;

        var asked = TeamsLauncher.StopAll();
        if (TeamsLauncher.IsRunning())
        {
            MessageBox.Show(
                asked == 0
                    ? "No Teams windows responded to close."
                    : $"Sent close to {asked} Teams window(s); some may still be exiting.",
                "TeamsISO — Stop Teams",
                MessageBoxButton.OK,
                MessageBoxImage.Information);
        }
        e.Handled = true;
    }

    /// <summary>
    /// Swap the maximize-button glyph between the "single rectangle" (when normal) and the
    /// "two-overlapping-rectangles" (when maximized) variants, matching the Windows 11
    /// caption-button conventions.
    /// </summary>
    private void OnWindowStateChanged(object? sender, EventArgs e)
    {
        if (FindName("MaximizeIcon") is not Path icon) return;
        icon.Data = WindowState == WindowState.Maximized
            // Two-rectangle "restore" glyph
            ? System.Windows.Media.Geometry.Parse("M 2,0 L 10,0 L 10,8 M 0,2 L 8,2 L 8,10 L 0,10 Z")
            // Single-rectangle "maximize" glyph
            : System.Windows.Media.Geometry.Parse("M 0,0 L 10,0 L 10,10 L 0,10 Z");
    }
}
