using System;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using Avalonia.VisualTree;
using ClaudeDo.Ui.ViewModels;

namespace ClaudeDo.Ui.Views.MissionControl;

public partial class MissionControlView : UserControl
{
    private const double SplitterSize = 6;
    private const double DefaultQueueWidth = 210;
    private const double MinQueueWidth = 160;
    private const double MinPaneWidth = 220;
    private const double MinPaneHeight = 140;

    private MissionControlViewModel? _vm;
    private GridLength _queueWidth = new(DefaultQueueWidth, GridUnitType.Pixel);

    public MissionControlView()
    {
        InitializeComponent();
        DataContextChanged += OnDataContextChanged;
        QueueSplitter.DragCompleted += (_, _) => _queueWidth = BodyGrid.ColumnDefinitions[2].Width;
    }

    private void OnSessionFlyoutOpening(object? sender, EventArgs e) => _ = _vm?.RefreshSessionTargetsAsync();

    // Ad-hoc ConPTY session: the view owns the folder picker, the VM only takes the chosen path.
    private async void BrowseForSessionAsync()
    {
        if (DataContext is not MissionControlViewModel vm) return;
        var topLevel = TopLevel.GetTopLevel(this);
        if (topLevel is null) return;

        var folders = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
        {
            Title = "Choose a directory",
            AllowMultiple = false,
        });
        if (folders.Count == 0) return;

        await vm.OpenAdHocConPtySessionAsync(folders[0].Path.LocalPath);
    }

    private void OnDataContextChanged(object? sender, EventArgs e)
    {
        if (_vm is not null)
        {
            _vm.Panes.CollectionChanged -= OnPanesChanged;
            _vm.PropertyChanged -= OnViewModelPropertyChanged;
            _vm.BrowseForSessionRequested = null;
        }

        _vm = DataContext as MissionControlViewModel;

        if (_vm is not null)
        {
            _vm.Panes.CollectionChanged += OnPanesChanged;
            _vm.PropertyChanged += OnViewModelPropertyChanged;
            _vm.BrowseForSessionRequested = BrowseForSessionAsync;
        }

        RebuildOverviewGrid();
        UpdateQueueColumn();
    }

    private void OnPanesChanged(object? sender, NotifyCollectionChangedEventArgs e) => RebuildOverviewGrid();

    private void OnViewModelPropertyChanged(object? sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(MissionControlViewModel.ColumnCount))
            RebuildOverviewGrid();
        else if (e.PropertyName == nameof(MissionControlViewModel.HasQueued))
            UpdateQueueColumn();
        else if (e.PropertyName == nameof(MissionControlViewModel.IsFocusMode))
            // The now-visible layout's hosts must re-steal their pane views from the hidden
            // one (see ConPtyPaneHost) — posted so it runs after the visibility change and
            // the TabControl's content presenter have gone through a layout pass.
            Avalonia.Threading.Dispatcher.UIThread.Post(ReclaimVisiblePaneHosts,
                Avalonia.Threading.DispatcherPriority.Loaded);
    }

    private void ReclaimVisiblePaneHosts()
    {
        foreach (var host in this.GetVisualDescendants().OfType<ConPtyPaneHost>())
            host.Reclaim();
    }

    // The queue column is Pixel-widthed (so the splitter can drag it) — when nothing is
    // queued it collapses to 0 instead of leaving a blank gap, and remembers the last
    // dragged width for the rest of this window's lifetime (not persisted beyond it).
    private void UpdateQueueColumn()
    {
        var queueColumn = BodyGrid.ColumnDefinitions[2];
        if (_vm?.HasQueued == true)
        {
            queueColumn.MinWidth = MinQueueWidth;
            queueColumn.Width = _queueWidth;
        }
        else
        {
            queueColumn.MinWidth = 0;
            queueColumn.Width = new GridLength(0, GridUnitType.Pixel);
        }
    }

    // Replaces the old UniformGrid with a real Grid + GridSplitters so panes resize
    // individually. Column splitters span every row (resize that whole column vs. its
    // neighbor); row splitters span every column. Rebuilt from scratch whenever the pane
    // count or column count changes — per-pane sizes are intentionally not preserved across
    // a rebuild (session-only resizing, reset to the default split when panes come/go).
    private void RebuildOverviewGrid()
    {
        OverviewGrid.Children.Clear();
        OverviewGrid.ColumnDefinitions.Clear();
        OverviewGrid.RowDefinitions.Clear();

        var panes = _vm?.Panes;
        if (panes is not { Count: > 0 }) return;

        var columns = Math.Max(1, _vm!.ColumnCount);
        var rows = (int)Math.Ceiling(panes.Count / (double)columns);

        for (var c = 0; c < columns; c++)
        {
            if (c > 0) OverviewGrid.ColumnDefinitions.Add(new ColumnDefinition(GridLength.Auto));
            OverviewGrid.ColumnDefinitions.Add(new ColumnDefinition(new GridLength(1, GridUnitType.Star)) { MinWidth = MinPaneWidth });
        }

        for (var r = 0; r < rows; r++)
        {
            if (r > 0) OverviewGrid.RowDefinitions.Add(new RowDefinition(GridLength.Auto));
            OverviewGrid.RowDefinitions.Add(new RowDefinition(new GridLength(1, GridUnitType.Star)) { MinHeight = MinPaneHeight });
        }

        var totalGridRows = rows * 2 - 1;
        var totalGridCols = columns * 2 - 1;

        for (var c = 1; c < columns; c++)
        {
            var splitter = new GridSplitter
            {
                Width = SplitterSize,
                Background = Brushes.Transparent,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
                ResizeDirection = GridResizeDirection.Columns,
                ResizeBehavior = GridResizeBehavior.PreviousAndNext,
            };
            Grid.SetColumn(splitter, c * 2 - 1);
            Grid.SetRow(splitter, 0);
            Grid.SetRowSpan(splitter, totalGridRows);
            OverviewGrid.Children.Add(splitter);
        }

        for (var r = 1; r < rows; r++)
        {
            var splitter = new GridSplitter
            {
                Height = SplitterSize,
                Background = Brushes.Transparent,
                HorizontalAlignment = HorizontalAlignment.Stretch,
                VerticalAlignment = VerticalAlignment.Stretch,
                ResizeDirection = GridResizeDirection.Rows,
                ResizeBehavior = GridResizeBehavior.PreviousAndNext,
            };
            Grid.SetColumn(splitter, 0);
            Grid.SetColumnSpan(splitter, totalGridCols);
            Grid.SetRow(splitter, r * 2 - 1);
            OverviewGrid.Children.Add(splitter);
        }

        for (var i = 0; i < panes.Count; i++)
        {
            var presenter = new ContentControl { Content = panes[i] };
            Grid.SetColumn(presenter, (i % columns) * 2);
            Grid.SetRow(presenter, (i / columns) * 2);
            OverviewGrid.Children.Add(presenter);
        }
    }
}
