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);

        // Subscribe to search events from tabs
        if (DataContext is MainWindowViewModel viewModel)
        {
            viewModel.PropertyChanged += OnViewModelPropertyChanged;
        }
    }

    private void OnViewModelPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(MainWindowViewModel.SelectedTab))
        {
            // Unsubscribe from old tab
            if (sender is MainWindowViewModel viewModel)
            {
                foreach (var tab in viewModel.Tabs)
                {
                    tab.SearchRequested -= OnTabSearchRequested;
                }

                // Subscribe to new selected tab
                if (viewModel.SelectedTab != null)
                {
                    viewModel.SelectedTab.SearchRequested += OnTabSearchRequested;
                }
            }
        }
    }

    private void OnTabSearchRequested(object? sender, SearchEventArgs e)
    {
        if (sender is not MarkdownTabViewModel tabViewModel)
            return;

        if (e.ClearHighlight)
        {
            // Clear search highlighting
            ClearSearchHighlight();
            return;
        }

        if (tabViewModel.IsPrettyView)
        {
            // Handle search in pretty view
            HandlePrettyViewSearch(e);
        }
        else
        {
            // Handle search in raw editor view
            HandleRawEditorSearch(tabViewModel, e);
        }
    }

    private void HandleRawEditorSearch(MarkdownTabViewModel tabViewModel, SearchEventArgs e)
    {
        var textEditor = this.GetVisualDescendants().OfType<TextEditor>()
            .FirstOrDefault(te => te.IsVisible && te.Name == "EditorTextBox");

        if (textEditor == null)
            return;

        if (e.ScrollToSelection && e.MatchPosition >= 0)
        {
            // Set selection and scroll to it
            textEditor.SelectionStart = e.MatchPosition;
            textEditor.SelectionLength = e.SearchText.Length;
            textEditor.CaretOffset = e.MatchPosition + e.SearchText.Length;
            
            // Scroll to caret
            var line = textEditor.Document.GetLineByOffset(textEditor.CaretOffset);
            textEditor.ScrollToLine(line.LineNumber);
        }
    }

    private void HandlePrettyViewSearch(SearchEventArgs e)
    {
        // For pretty view, we could highlight matches visually
        // For now, we'll just scroll to the match position if possible
        // Note: SelectableTextBlock doesn't have direct scroll-to-position support,
        // so this is a simplified implementation
    }

    private void ClearSearchHighlight()
    {
        // Clear any search highlighting in both views
        // This is a placeholder for future highlighting implementation
    }

    /// <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();

            // Subscribe to selected tab changes
            viewModel.PropertyChanged += OnViewModelPropertyChanged;
            if (viewModel.SelectedTab != null)
            {
                viewModel.SelectedTab.SearchRequested += OnTabSearchRequested;
            }
        }
    }

    /// <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;
            }
        }
    }
}