using System.ComponentModel;
using Avalonia.Controls;
using Avalonia.Interactivity;
using AvaloniaEdit;
using AvaloniaEdit.TextMate;
using GsaEditor.ViewModels;
using TextMateSharp.Grammars;

namespace GsaEditor.Views;

public partial class MainWindow : Window
{
    private bool _forceClose;
    private TextEditor? _textEditor;
    private TextMate.Installation? _textMateInstall;
    private readonly RegistryOptions _registryOptions;

    public MainWindow()
    {
        InitializeComponent();

        _registryOptions = new RegistryOptions(ThemeName.DarkPlus);

        _textEditor = this.FindControl<TextEditor>("TextEditor");
        if (_textEditor != null)
        {
            _textMateInstall = _textEditor.InstallTextMate(_registryOptions);
        }
    }

    protected override void OnLoaded(RoutedEventArgs e)
    {
        base.OnLoaded(e);

        if (DataContext is MainWindowViewModel vm)
        {
            vm.SetWindow(this);
            vm.PropertyChanged += ViewModel_PropertyChanged;
        }
    }

    private void ViewModel_PropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (sender is not MainWindowViewModel vm) return;

        if (e.PropertyName == nameof(MainWindowViewModel.PreviewText))
        {
            if (_textEditor != null && vm.PreviewText != null)
            {
                _textEditor.Text = vm.PreviewText;
            }
            else if (_textEditor != null)
            {
                _textEditor.Text = string.Empty;
            }
        }

        if (e.PropertyName == nameof(MainWindowViewModel.SelectedEntry))
        {
            ApplySyntaxHighlighting(vm);
        }

        if (e.PropertyName == nameof(MainWindowViewModel.SelectedNode))
        {
            // Reflect programmatic selection (e.g. from search results) in the tree.
            // Posted so newly expanded parent containers are realized first.
            var tree = this.FindControl<TreeView>("ArchiveTree");
            if (tree != null && vm.SelectedNode != null && !ReferenceEquals(tree.SelectedItem, vm.SelectedNode))
            {
                Avalonia.Threading.Dispatcher.UIThread.Post(
                    () => tree.SelectedItem = vm.SelectedNode,
                    Avalonia.Threading.DispatcherPriority.Background);
            }
        }
    }

    private void ApplySyntaxHighlighting(MainWindowViewModel vm)
    {
        if (_textMateInstall == null || vm.SelectedEntry == null) return;

        var alias = vm.SelectedEntry.Alias;
        var ext = System.IO.Path.GetExtension(alias).ToLowerInvariant();

        // Map file extension to a TextMate language scope
        var language = _registryOptions.GetLanguageByExtension(ext);
        if (language != null)
        {
            _textMateInstall.SetGrammar(_registryOptions.GetScopeByLanguageId(language.Id));
        }
        else
        {
            _textMateInstall.SetGrammar(null);
        }
    }

    /// <summary>
    /// Called by the ViewModel to retrieve the current text from the editor.
    /// </summary>
    public string? GetEditorText()
    {
        return _textEditor?.Text;
    }

    private void TreeView_SelectionChanged(object? sender, SelectionChangedEventArgs e)
    {
        if (DataContext is MainWindowViewModel vm && sender is TreeView tree)
        {
            vm.SelectedNode = tree.SelectedItem as EntryTreeNodeViewModel;
        }
    }

    protected override async void OnClosing(WindowClosingEventArgs e)
    {
        base.OnClosing(e);

        if (_forceClose) return;

        if (DataContext is MainWindowViewModel vm && vm.IsDirty)
        {
            e.Cancel = true;
            var confirmed = await Helpers.Dialogs.ConfirmAsync(this, "Unsaved Changes",
                "You have unsaved changes. Close without saving?");
            if (confirmed)
            {
                _forceClose = true;
                Close();
            }
        }
    }
}
