using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ClawdDotNet.Desktop.ViewModels;

namespace ClawdDotNet.Desktop.Views;

public partial class AgentsPageView : UserControl
{
    private AgentsPageViewModel? _viewModel;

    public AgentsPageView()
    {
        InitializeComponent();

        // Ein Zug am Teiler ist erst zu Ende, wenn die Maus losgelassen wird. Waehrend
        // des Ziehens zu speichern hiesse, fuer eine Bewegung ein paar Dutzend Mal die
        // Einstellungsdatei zu schreiben.
        TopSplitter.DragCompleted += (_, _) => SaveSplits();
        BottomSplitter.DragCompleted += (_, _) => SaveSplits();
        VerticalSplitter.DragCompleted += (_, _) => SaveSplits();
    }

    protected override void OnDataContextChanged(EventArgs e)
    {
        base.OnDataContextChanged(e);

        if (DataContext is not AgentsPageViewModel vm) return;

        _viewModel = vm;
        vm.RequestAddAgentDialog += OnRequestAddAgentDialog;
        vm.RequestTextEditorDialog += OnRequestTextEditorDialog;

        ApplySavedSplits(vm);
    }

    /// <summary>
    /// Setzt die gespeicherten Teilerstellungen.
    ///
    /// <para>Von Hand und nicht per Bindung: <see cref="ColumnDefinition"/> und
    /// <see cref="RowDefinition"/> liegen nicht im Sichtbarkeitsbaum und erben deshalb
    /// keinen DataContext. Eine Bindung auf ihre Breite bliebe ohne Wirkung — und zwar
    /// ohne Fehlermeldung.</para>
    /// </summary>
    private void ApplySavedSplits(AgentsPageViewModel vm)
    {
        SetRatio(TopGrid.ColumnDefinitions[0], TopGrid.ColumnDefinitions[2], vm.SplitTopList);
        SetRatio(BottomGrid.ColumnDefinitions[0], BottomGrid.ColumnDefinitions[2], vm.SplitBottomList);

        OuterGrid.RowDefinitions[0].Height = new GridLength(vm.SplitVertical, GridUnitType.Star);
        OuterGrid.RowDefinitions[2].Height = new GridLength(1 - vm.SplitVertical, GridUnitType.Star);
    }

    private static void SetRatio(ColumnDefinition first, ColumnDefinition second, double ratio)
    {
        first.Width = new GridLength(ratio, GridUnitType.Star);
        second.Width = new GridLength(1 - ratio, GridUnitType.Star);
    }

    private void SaveSplits()
    {
        if (_viewModel is null) return;

        _viewModel.SaveSplits(
            RowRatio(OuterGrid.RowDefinitions[0], OuterGrid.RowDefinitions[2]),
            ColumnRatio(TopGrid.ColumnDefinitions[0], TopGrid.ColumnDefinitions[2]),
            ColumnRatio(BottomGrid.ColumnDefinitions[0], BottomGrid.ColumnDefinitions[2]));
    }

    /// <summary>
    /// Das Verhaeltnis wird aus den tatsaechlichen Pixelbreiten gebildet, nicht aus den
    /// Sternwerten: Der GridSplitter setzt beim Ziehen mitunter absolute Breiten, und
    /// dann stuenden in den Sternwerten noch die Zahlen von vor dem Zug.
    /// </summary>
    private static double ColumnRatio(ColumnDefinition first, ColumnDefinition second)
        => Ratio(first.ActualWidth, second.ActualWidth);

    private static double RowRatio(RowDefinition first, RowDefinition second)
        => Ratio(first.ActualHeight, second.ActualHeight);

    private static double Ratio(double first, double second)
    {
        var total = first + second;
        return total > 0 ? first / total : 0.5;
    }

    private async Task<AddAgentResultData?> OnRequestAddAgentDialog(AddAgentViewModel vm)
    {
        if (TopLevel.GetTopLevel(this) is not Window window) return null;

        var dialog = new AddAgentWindow { DataContext = vm };
        await dialog.ShowDialog(window);
        return vm.Result;
    }

    private async Task<string?> OnRequestTextEditorDialog(string title, string text)
    {
        if (TopLevel.GetTopLevel(this) is not Window window) return null;

        return await TextEditorWindow.ShowAsync(window, title, text);
    }
}
