using System;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.VisualTree;
using AvaloniaEdit;
using MarkdownEditor.Constants;
using MarkdownEditor.ViewModels;

namespace MarkdownEditor.Views;

/// <summary>
/// Main application window.
/// Handles initialization and coordination between the view and view model.
/// </summary>
public partial class MainWindow : Window
{
    private bool _isClosingConfirmed = false;

    /// <summary>
    /// Initializes a new instance of the <see cref="MainWindow"/> class.
    /// </summary>
    public MainWindow()
    {
        InitializeComponent();

        // Subscribe to pointer pressed to capture selection before command executes
        this.AddHandler(Button.PointerPressedEvent, OnButtonPointerPressed, Avalonia.Interactivity.RoutingStrategies.Tunnel);
    }

    /// <inheritdoc/>
    protected override void OnOpened(EventArgs e)
    {
        base.OnOpened(e);

        if (DataContext is MainWindowViewModel viewModel)
        {
            viewModel.StorageProvider = StorageProvider;
            // Restore session after StorageProvider is set
            _ = viewModel.RestoreSessionAsync();
        }
    }

    /// <inheritdoc/>
    protected override async void OnClosing(WindowClosingEventArgs e)
    {
        if (DataContext is not MainWindowViewModel viewModel)
        {
            base.OnClosing(e);
            return;
        }

        // If we've already confirmed the close (from a previous call), just save session and close
        if (_isClosingConfirmed)
        {
            await viewModel.SaveSessionAsync();
            base.OnClosing(e);
            return;
        }

        // Check for unsaved changes
        if (viewModel.HasUnsavedChanges())
        {
            // Cancel the close event to prevent immediate closing
            e.Cancel = true;

            // Show save confirmation dialog
            var unsavedCount = viewModel.GetUnsavedChangesCount();
            var message = unsavedCount == 1
                ? AppConstants.Messages.SaveChangesBeforeClose
                : string.Format(AppConstants.Messages.SaveChangesBeforeCloseMultiple, unsavedCount);

            var dialog = new SaveConfirmationDialog(message);
            await dialog.ShowDialog<bool>(this);
            var result = dialog.Result;

            switch (result)
            {
                case SaveConfirmationResult.Save:
                    // User wants to save - save all unsaved changes
                    var saved = await viewModel.SaveAllUnsavedChangesAsync();
                    if (saved)
                    {
                        // All files saved successfully - mark as confirmed and close
                        _isClosingConfirmed = true;
                        await viewModel.SaveSessionAsync();
                        Close();
                    }
                    // If save was cancelled, keep the window open (e.Cancel is already true)
                    // Don't call base.OnClosing since we're cancelling
                    return;

                case SaveConfirmationResult.DontSave:
                    // User doesn't want to save - mark as confirmed and close
                    _isClosingConfirmed = true;
                    await viewModel.SaveSessionAsync();
                    Close();
                    // Don't call base.OnClosing here - Close() will trigger OnClosing again
                    return;

                case SaveConfirmationResult.Cancel:
                default:
                    // User cancelled - keep the window open (e.Cancel is already true)
                    // Don't call base.OnClosing since we're cancelling
                    return;
            }
        }
        else
        {
            // No unsaved changes - just save session and close normally
            await viewModel.SaveSessionAsync();
        }

        base.OnClosing(e);
    }

    /// <summary>
    /// Handles pointer pressed events to capture text selection before formatting commands execute.
    /// This is necessary because toolbar buttons take focus, losing the text selection.
    /// </summary>
    private void OnButtonPointerPressed(object? sender, Avalonia.Input.PointerPressedEventArgs e)
    {
        // Walk up the visual tree to find the Button
        Button? button = null;
        if (e.Source is Control sourceControl)
        {
            button = sourceControl.GetVisualAncestors().OfType<Button>().FirstOrDefault();
        }

        // Only process toolbar buttons
        if (button != null && button.Classes.Contains("toolbar-btn"))
        {
            // Find the TextEditor and update selection in ViewModel before command executes
            if (DataContext is MainWindowViewModel mainViewModel && mainViewModel.SelectedTab != null)
            {
                var textEditor = this.GetVisualDescendants().OfType<TextEditor>()
                    .FirstOrDefault(te => te.IsVisible);

                if (textEditor != null)
                {
                    mainViewModel.SelectedTab.SelectionStart = textEditor.SelectionStart;
                    mainViewModel.SelectedTab.SelectionEnd = textEditor.SelectionStart + textEditor.SelectionLength;
                }
            }
        }
    }

    /// <summary>
    /// Handles the Insert Hyperlink button click.
    /// </summary>
    private async void OnInsertHyperlink(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button && button.Tag is MarkdownTabViewModel tabViewModel)
        {
            CaptureSelection();

            var dialog = new UrlInputDialog("Insert Hyperlink", "Enter the URL for the link:");
            var result = await dialog.ShowDialog<bool>(this);

            if (dialog.IsConfirmed && !string.IsNullOrWhiteSpace(dialog.Url))
            {
                tabViewModel.InsertHyperlink(dialog.Url);
            }
        }
    }

    /// <summary>
    /// Handles the Insert Image button click.
    /// </summary>
    private async void OnInsertImage(object? sender, RoutedEventArgs e)
    {
        if (sender is Button button && button.Tag is MarkdownTabViewModel tabViewModel)
        {
            CaptureSelection();

            var dialog = new UrlInputDialog("Insert Image", "Enter the URL for the image:");
            var result = await dialog.ShowDialog<bool>(this);

            if (dialog.IsConfirmed && !string.IsNullOrWhiteSpace(dialog.Url))
            {
                tabViewModel.InsertImage(dialog.Url);
            }
        }
    }

    /// <summary>
    /// Captures the current text selection from the visible text editor.
    /// </summary>
    private void CaptureSelection()
    {
        if (DataContext is MainWindowViewModel mainViewModel && mainViewModel.SelectedTab != null)
        {
            var textEditor = this.GetVisualDescendants().OfType<TextEditor>()
                .FirstOrDefault(te => te.IsVisible);

            if (textEditor != null)
            {
                mainViewModel.SelectedTab.SelectionStart = textEditor.SelectionStart;
                mainViewModel.SelectedTab.SelectionEnd = textEditor.SelectionStart + textEditor.SelectionLength;
            }
        }
    }
}