using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;

namespace Sonex.Client.Controls.SceneCanvas;

public sealed partial class SceneCanvasToolBar : UserControl
{
    private int _activeLayoutId;
    private int _selectedCount;
    private bool _isUpdatingSelectionEditors;
    private bool _isUpdatingLayoutControls;
    private bool _isUpdatingMagnetLayoutControls;
    private bool _isEditModeEnabled = true;
    private bool _isRulerModeEnabled;
    private bool _isGridVisible = true;
    private bool _areRulersVisible = true;
    private readonly List<SceneCanvasLayoutInfo> _layouts = [];
    private readonly List<int> _magnetLayoutIds = [];
    private bool _magnetActiveLayoutOnly = true;

    public SceneCanvasToolBar()
    {
        InitializeComponent();
        SetLayouts([], 0);
        UpdateEditingControlsState();
    }

    public event EventHandler<bool>? MagnetToggled;

    public event EventHandler<SceneCanvasMagnetLayoutsChangedEventArgs>? MagnetLayoutsChanged;

    public event EventHandler<int>? ActiveLayoutChanged;

    public event EventHandler? AddLayoutRequested;

    public event EventHandler<int>? RenameLayoutRequested;

    public event EventHandler<int>? DeleteLayoutRequested;

    public event EventHandler<int>? MoveSelectionToLayoutRequested;

    public event EventHandler<int>? MoveLayoutUpRequested;

    public event EventHandler<int>? MoveLayoutDownRequested;

    public event EventHandler? ZoomInRequested;

    public event EventHandler? ZoomOutRequested;

    public event EventHandler? FitToObjectsRequested;

    public event EventHandler? ZoomToSelectionRequested;

    public event EventHandler? MatchSelectionWidthRequested;

    public event EventHandler? MatchSelectionHeightRequested;

    public event EventHandler? RotateSelectionLeftRequested;

    public event EventHandler? RotateSelectionRightRequested;

    public event EventHandler<SceneCanvas.SelectionAlignment>? AlignmentRequested;

    public event EventHandler<SceneCanvas.SelectionLayout>? LayoutRequested;

    public event EventHandler? CutRequested;

    public event EventHandler? CopyRequested;

    public event EventHandler? PasteRequested;

    public event EventHandler? DeleteRequested;

    public event EventHandler? CloneRequested;

    public event EventHandler<SceneCanvasShapePropertiesChangedEventArgs>? ShapePropertiesChanged;

    public event EventHandler<SceneCanvasLinePropertiesChangedEventArgs>? LinePropertiesChanged;

    public event EventHandler? UndoRequested;

    public event EventHandler? BringToFrontRequested;

    public event EventHandler? SendToBackRequested;

    public event EventHandler<SceneCanvasMoveSelectionRequestedEventArgs>? MoveSelectionRequested;

    public event EventHandler<bool>? EditModeChanged;

    public event EventHandler<bool>? RulerModeChanged;

    public event EventHandler<bool>? GridVisibilityChanged;

    public event EventHandler<bool>? RulersVisibilityChanged;

    public event EventHandler? AddVerticalGuideRequested;

    public event EventHandler? AddHorizontalGuideRequested;

    public bool IsMagnetEnabled
    {
        get => _MagnetSplitButton?.IsChecked == true;
        set
        {
            if (_MagnetSplitButton != null)
            {
                _MagnetSplitButton.IsChecked = value;
            }
        }
    }

    public int ActiveLayoutId
    {
        get => _activeLayoutId;
        set => SetActiveLayout(value, false);
    }

    public int ActiveLayer
    {
        get => ActiveLayoutId;
        set => ActiveLayoutId = value;
    }

    public bool IsEditModeEnabled
    {
        get
        {
            if (_EditModeToggleButton != null)
            {
                _isEditModeEnabled = _EditModeToggleButton.IsChecked == true;
            }

            return _isEditModeEnabled;
        }
        set
        {
            _isEditModeEnabled = value;
            if (_EditModeToggleButton != null)
            {
                _EditModeToggleButton.IsChecked = value;
            }

            UpdateEditingControlsState();
        }
    }

    public bool IsRulerModeEnabled
    {
        get
        {
            if (_RulerModeToggleButton != null)
            {
                _isRulerModeEnabled = _RulerModeToggleButton.IsChecked == true;
            }

            return _isRulerModeEnabled;
        }
        set
        {
            _isRulerModeEnabled = value;
            if (_RulerModeToggleButton != null)
            {
                _RulerModeToggleButton.IsChecked = value;
            }

            UpdateEditingControlsState();
        }
    }

    public bool IsGridVisible
    {
        get
        {
            if (_GridVisibilityToggleButton != null)
            {
                _isGridVisible = _GridVisibilityToggleButton.IsChecked == true;
            }

            return _isGridVisible;
        }
        set
        {
            _isGridVisible = value;
            if (_GridVisibilityToggleButton != null)
            {
                _GridVisibilityToggleButton.IsChecked = value;
            }
        }
    }

    public bool AreRulersVisible
    {
        get
        {
            if (_RulersVisibilityToggleButton != null)
            {
                _areRulersVisible = _RulersVisibilityToggleButton.IsChecked == true;
            }

            return _areRulersVisible;
        }
        set
        {
            _areRulersVisible = value;
            if (_RulersVisibilityToggleButton != null)
            {
                _RulersVisibilityToggleButton.IsChecked = value;
            }
        }
    }

    public void SetLayouts(IEnumerable<SceneCanvasLayoutInfo> layouts, int activeLayoutId)
    {
        _layouts.Clear();
        foreach (var layout in layouts)
        {
            if (layout == null)
            {
                continue;
            }

            _layouts.Add(new SceneCanvasLayoutInfo(layout.Id, layout.Name));
        }

        if (_layouts.Count == 0)
        {
            _layouts.Add(new SceneCanvasLayoutInfo(0, "Layout 0"));
        }

        _activeLayoutId = ResolveLayoutId(activeLayoutId);
        SyncMagnetLayoutSelectionAfterLayoutsChanged();
        RefreshLayoutControls();
    }

    public void SetMagnetLayoutSelection(bool activeLayoutOnly, IEnumerable<int>? layoutIds)
    {
        _magnetActiveLayoutOnly = activeLayoutOnly;
        _magnetLayoutIds.Clear();
        if (layoutIds != null)
        {
            foreach (var layoutId in layoutIds)
            {
                if (_magnetLayoutIds.Contains(layoutId))
                {
                    continue;
                }

                _magnetLayoutIds.Add(layoutId);
            }
        }

        SyncMagnetLayoutSelectionAfterLayoutsChanged();
        RebuildMagnetLayoutOptions();
    }

    public void SetSelectionContext(SceneCanvasObject? selectedObject, int selectedCount)
    {
        var previousSelectedCount = _selectedCount;

        _selectedCount = Math.Max(0, selectedCount);
        _ShapePropertiesGroup.Visibility = Visibility.Collapsed;
        _LinePropertiesGroup.Visibility = Visibility.Collapsed;

        if (previousSelectedCount != _selectedCount)
        {
            UpdateEditingControlsState();
        }
    }

    private void MagnetSplitButton_IsCheckedChanged(ToggleSplitButton sender, ToggleSplitButtonIsCheckedChangedEventArgs args)
    {
        MagnetToggled?.Invoke(this, IsMagnetEnabled);
    }

    private void ActiveLayoutComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (_isUpdatingLayoutControls)
        {
            return;
        }

        if (_ActiveLayoutComboBox.SelectedItem is not SceneCanvasLayoutInfo selectedLayout)
        {
            return;
        }

        SetActiveLayout(selectedLayout.Id, true);
    }

    private void ConfirmMoveSelectionButton_Click(object sender, RoutedEventArgs e)
    {
        if (_MoveSelectionLayoutComboBox.SelectedItem is not SceneCanvasLayoutInfo selectedLayout)
        {
            return;
        }

        MoveSelectionToLayoutRequested?.Invoke(this, selectedLayout.Id);
        _MoveSelectionLayoutButton?.Flyout?.Hide();
    }

    private void AddLayoutButton_Click(object sender, RoutedEventArgs e)
    {
        AddLayoutRequested?.Invoke(this, EventArgs.Empty);
    }

    private void RenameLayoutButton_Click(object sender, RoutedEventArgs e)
    {
        RenameLayoutRequested?.Invoke(this, _activeLayoutId);
    }

    private void DeleteLayoutButton_Click(object sender, RoutedEventArgs e)
    {
        DeleteLayoutRequested?.Invoke(this, _activeLayoutId);
    }

    private void MoveLayoutUpButton_Click(object sender, RoutedEventArgs e)
    {
        MoveLayoutUpRequested?.Invoke(this, _activeLayoutId);
    }

    private void MoveLayoutDownButton_Click(object sender, RoutedEventArgs e)
    {
        MoveLayoutDownRequested?.Invoke(this, _activeLayoutId);
    }

    private void ZoomInButton_Click(object sender, RoutedEventArgs e)
    {
        ZoomInRequested?.Invoke(this, EventArgs.Empty);
    }

    private void ZoomOutButton_Click(object sender, RoutedEventArgs e)
    {
        ZoomOutRequested?.Invoke(this, EventArgs.Empty);
    }

    private void FitToObjectsButton_Click(object sender, RoutedEventArgs e)
    {
        FitToObjectsRequested?.Invoke(this, EventArgs.Empty);
    }

    private void ZoomToSelectionButton_Click(object sender, RoutedEventArgs e)
    {
        ZoomToSelectionRequested?.Invoke(this, EventArgs.Empty);
    }

    private void SetSelectionWidthButton_Click(object sender, RoutedEventArgs e)
    {
        MatchSelectionWidthRequested?.Invoke(this, EventArgs.Empty);
    }

    private void SetSelectionHeightButton_Click(object sender, RoutedEventArgs e)
    {
        MatchSelectionHeightRequested?.Invoke(this, EventArgs.Empty);
    }

    private void RotateSelectionLeftButton_Click(object sender, RoutedEventArgs e)
    {
        RotateSelectionLeftRequested?.Invoke(this, EventArgs.Empty);
    }

    private void RotateSelectionRightButton_Click(object sender, RoutedEventArgs e)
    {
        RotateSelectionRightRequested?.Invoke(this, EventArgs.Empty);
    }

    private void AlignButton_Click(object sender, RoutedEventArgs e)
    {
        if (sender is not FrameworkElement element)
        {
            return;
        }

        if (!TryParseAlignment(element.Tag, out var alignment))
        {
            return;
        }

        AlignmentRequested?.Invoke(this, alignment);
    }

    private void LayoutButton_Click(object sender, RoutedEventArgs e)
    {
        if (sender is not FrameworkElement element)
        {
            return;
        }

        if (!TryParseLayout(element.Tag, out var layout))
        {
            return;
        }

        LayoutRequested?.Invoke(this, layout);
    }

    private void CutButton_Click(object sender, RoutedEventArgs e)
    {
        CutRequested?.Invoke(this, EventArgs.Empty);
    }

    private void CopyButton_Click(object sender, RoutedEventArgs e)
    {
        CopyRequested?.Invoke(this, EventArgs.Empty);
    }

    private void PasteButton_Click(object sender, RoutedEventArgs e)
    {
        PasteRequested?.Invoke(this, EventArgs.Empty);
    }

    private void DeleteButton_Click(object sender, RoutedEventArgs e)
    {
        DeleteRequested?.Invoke(this, EventArgs.Empty);
    }

    private void CloneButton_Click(object sender, RoutedEventArgs e)
    {
        CloneRequested?.Invoke(this, EventArgs.Empty);
    }

    private void UndoButton_Click(object sender, RoutedEventArgs e)
    {
        UndoRequested?.Invoke(this, EventArgs.Empty);
    }

    private void BringToFrontButton_Click(object sender, RoutedEventArgs e)
    {
        BringToFrontRequested?.Invoke(this, EventArgs.Empty);
    }

    private void AddVerticalGuideButton_Click(object sender, RoutedEventArgs e)
    {
        AddVerticalGuideRequested?.Invoke(this, EventArgs.Empty);
    }

    private void AddHorizontalGuideButton_Click(object sender, RoutedEventArgs e)
    {
        AddHorizontalGuideRequested?.Invoke(this, EventArgs.Empty);
    }

    private void SendToBackButton_Click(object sender, RoutedEventArgs e)
    {
        SendToBackRequested?.Invoke(this, EventArgs.Empty);
    }

    private void ApplyMoveDeltaButton_Click(object sender, RoutedEventArgs e)
    {
        if (_isUpdatingSelectionEditors || !TryGetMoveDeltaValues(out var delta))
        {
            return;
        }

        MoveSelectionRequested?.Invoke(
            this,
            new SceneCanvasMoveSelectionRequestedEventArgs(delta.DeltaX, delta.DeltaY));
    }

    private void EditModeToggleButton_Changed(object sender, RoutedEventArgs e)
    {
        _isEditModeEnabled = _EditModeToggleButton?.IsChecked == true;
        UpdateEditingControlsState();
        EditModeChanged?.Invoke(this, _isEditModeEnabled);
    }

    private void RulerModeToggleButton_Changed(object sender, RoutedEventArgs e)
    {
        _isRulerModeEnabled = _RulerModeToggleButton?.IsChecked == true;
        UpdateEditingControlsState();
        RulerModeChanged?.Invoke(this, _isRulerModeEnabled);
    }

    private void GridVisibilityToggleButton_Changed(object sender, RoutedEventArgs e)
    {
        _isGridVisible = _GridVisibilityToggleButton?.IsChecked == true;
        GridVisibilityChanged?.Invoke(this, _isGridVisible);
    }

    private void RulersVisibilityToggleButton_Changed(object sender, RoutedEventArgs e)
    {
        _areRulersVisible = _RulersVisibilityToggleButton?.IsChecked == true;
        RulersVisibilityChanged?.Invoke(this, _areRulersVisible);
    }

    private void ShapeNumberBox_ValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args)
    {
        if (_isUpdatingSelectionEditors || !TryGetShapeValues(out var shapeValues))
        {
            return;
        }

        ShapePropertiesChanged?.Invoke(
            this,
            new SceneCanvasShapePropertiesChangedEventArgs(
                shapeValues.X,
                shapeValues.Y,
                shapeValues.Z,
                shapeValues.Width,
                shapeValues.Height,
                shapeValues.RotationDegrees));
    }

    private void LineNumberBox_ValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args)
    {
        if (_isUpdatingSelectionEditors || !TryGetLineValues(out var lineValues))
        {
            return;
        }

        LinePropertiesChanged?.Invoke(
            this,
            new SceneCanvasLinePropertiesChangedEventArgs(
                lineValues.StartX,
                lineValues.StartY,
                lineValues.StartZ,
                lineValues.EndX,
                lineValues.EndY,
                lineValues.EndZ,
                lineValues.Thickness));
    }

    private void SetActiveLayout(int layoutId, bool raiseEvent)
    {
        var resolved = ResolveLayoutId(layoutId);
        if (_activeLayoutId == resolved && !raiseEvent)
        {
            RefreshLayoutControls();
            return;
        }

        _activeLayoutId = resolved;
        RefreshLayoutControls();

        if (raiseEvent)
        {
            ActiveLayoutChanged?.Invoke(this, resolved);
        }
    }

    private int ResolveLayoutId(int layoutId)
    {
        foreach (var layout in _layouts)
        {
            if (layout.Id == layoutId)
            {
                return layout.Id;
            }
        }

        return _layouts.Count > 0 ? _layouts[0].Id : 0;
    }

    private void RefreshLayoutControls()
    {
        if (_ActiveLayoutComboBox == null
            || _MoveSelectionLayoutComboBox == null
            || _AddLayoutButton == null
            || _RenameLayoutButton == null
            || _DeleteLayoutButton == null
            || _MoveLayoutUpButton == null
            || _MoveLayoutDownButton == null
            || _MoveSelectionLayoutButton == null
            || _ConfirmMoveSelectionButton == null)
        {
            return;
        }

        _isUpdatingLayoutControls = true;
        try
        {
            _ActiveLayoutComboBox.ItemsSource = null;
            _ActiveLayoutComboBox.ItemsSource = _layouts;

            _MoveSelectionLayoutComboBox.ItemsSource = null;
            _MoveSelectionLayoutComboBox.ItemsSource = _layouts;

            var activeLayout = FindLayoutById(_activeLayoutId) ?? (_layouts.Count > 0 ? _layouts[0] : null);
            _ActiveLayoutComboBox.SelectedItem = activeLayout;

            if (activeLayout != null)
            {
                _MoveSelectionLayoutComboBox.SelectedItem = activeLayout;
            }
            else
            {
                _MoveSelectionLayoutComboBox.SelectedItem = null;
            }
        }
        finally
        {
            _isUpdatingLayoutControls = false;
        }

        var activeLayoutName = GetActiveLayoutName();
        var canEdit = _isEditModeEnabled && !_isRulerModeEnabled;
        var hasLayouts = _layouts.Count > 0;
        var canDelete = _layouts.Count > 1;
        var canMove = canEdit && _selectedCount > 0 && hasLayouts;
        var activeLayoutIndex = GetActiveLayoutIndex();
        var canMoveLayoutUp = canEdit && activeLayoutIndex > 0;
        var canMoveLayoutDown = canEdit && activeLayoutIndex >= 0 && activeLayoutIndex < (_layouts.Count - 1);

        _ActiveLayoutComboBox.IsEnabled = hasLayouts;
        _AddLayoutButton.IsEnabled = canEdit;
        _RenameLayoutButton.IsEnabled = canEdit && hasLayouts;
        _DeleteLayoutButton.IsEnabled = canEdit && canDelete;
        _MoveLayoutUpButton.IsEnabled = canMoveLayoutUp;
        _MoveLayoutDownButton.IsEnabled = canMoveLayoutDown;
        _MoveSelectionLayoutButton.IsEnabled = canMove;
        _MoveSelectionLayoutComboBox.IsEnabled = canMove;
        _ConfirmMoveSelectionButton.IsEnabled = canMove;

        ToolTipService.SetToolTip(_ActiveLayoutComboBox, string.IsNullOrWhiteSpace(activeLayoutName)
            ? "Layouts"
            : $"Active layout: {activeLayoutName}");
        RebuildMagnetLayoutOptions();
        RefreshActionControls();
    }

    private void MagnetActiveLayoutOnlyCheckBox_Changed(object sender, RoutedEventArgs e)
    {
        if (_isUpdatingMagnetLayoutControls)
        {
            return;
        }

        _magnetActiveLayoutOnly = _MagnetActiveLayoutOnlyCheckBox?.IsChecked == true;
        SyncMagnetLayoutSelectionAfterLayoutsChanged();
        RebuildMagnetLayoutOptions();
        RaiseMagnetLayoutsChanged();
    }

    private void MagnetLayoutCheckBox_Changed(object sender, RoutedEventArgs e)
    {
        if (_isUpdatingMagnetLayoutControls || sender is not CheckBox checkBox)
        {
            return;
        }

        if (checkBox.Tag is not int layoutId)
        {
            return;
        }

        if (checkBox.IsChecked == true)
        {
            if (!_magnetLayoutIds.Contains(layoutId))
            {
                _magnetLayoutIds.Add(layoutId);
            }
        }
        else
        {
            _magnetLayoutIds.Remove(layoutId);
        }

        SyncMagnetLayoutSelectionAfterLayoutsChanged();
        RebuildMagnetLayoutOptions();
        RaiseMagnetLayoutsChanged();
    }

    private void SyncMagnetLayoutSelectionAfterLayoutsChanged()
    {
        for (var i = _magnetLayoutIds.Count - 1; i >= 0; i--)
        {
            if (FindLayoutById(_magnetLayoutIds[i]) != null)
            {
                continue;
            }

            _magnetLayoutIds.RemoveAt(i);
        }

        if (_magnetLayoutIds.Count == 0 && _layouts.Count > 0)
        {
            _magnetLayoutIds.Add(_activeLayoutId);
        }
    }

    private void RebuildMagnetLayoutOptions()
    {
        if (_MagnetActiveLayoutOnlyCheckBox == null
            || _MagnetLayoutsPanel == null
            || _MagnetSplitButton == null)
        {
            return;
        }

        _isUpdatingMagnetLayoutControls = true;
        try
        {
            _MagnetActiveLayoutOnlyCheckBox.IsChecked = _magnetActiveLayoutOnly;
            _MagnetLayoutsPanel.Children.Clear();

            foreach (var layout in _layouts)
            {
                var checkBox = new CheckBox
                {
                    Content = layout.Name,
                    Tag = layout.Id,
                    IsChecked = _magnetLayoutIds.Contains(layout.Id)
                };
                checkBox.Checked += MagnetLayoutCheckBox_Changed;
                checkBox.Unchecked += MagnetLayoutCheckBox_Changed;
                _MagnetLayoutsPanel.Children.Add(checkBox);
            }

            _MagnetLayoutsPanel.IsHitTestVisible = !_magnetActiveLayoutOnly;
            _MagnetLayoutsPanel.Opacity = _magnetActiveLayoutOnly ? 0.55d : 1d;
            ToolTipService.SetToolTip(_MagnetSplitButton, BuildMagnetLayoutScopeToolTip());
        }
        finally
        {
            _isUpdatingMagnetLayoutControls = false;
        }
    }

    private string BuildMagnetLayoutScopeToolTip()
    {
        if (_magnetActiveLayoutOnly)
        {
            return "Toggle snap (Ctrl+M)\nScope: active layout";
        }

        if (_magnetLayoutIds.Count == 0)
        {
            return "Toggle snap (Ctrl+M)\nScope: no layouts";
        }

        var names = new List<string>();
        foreach (var layoutId in _magnetLayoutIds)
        {
            var layout = FindLayoutById(layoutId);
            if (layout != null)
            {
                names.Add(layout.Name);
            }
        }

        return names.Count == 0
            ? "Toggle snap (Ctrl+M)\nScope: selected layouts"
            : $"Toggle snap (Ctrl+M)\nScope: {string.Join(", ", names)}";
    }

    private void RaiseMagnetLayoutsChanged()
    {
        var selectedLayoutIds = new List<int>(_magnetLayoutIds.Count);
        foreach (var layoutId in _magnetLayoutIds)
        {
            selectedLayoutIds.Add(layoutId);
        }

        MagnetLayoutsChanged?.Invoke(
            this,
            new SceneCanvasMagnetLayoutsChangedEventArgs(_magnetActiveLayoutOnly, selectedLayoutIds));
    }

    private SceneCanvasLayoutInfo? FindLayoutById(int layoutId)
    {
        foreach (var layout in _layouts)
        {
            if (layout.Id == layoutId)
            {
                return layout;
            }
        }

        return null;
    }

    private string GetActiveLayoutName()
    {
        foreach (var layout in _layouts)
        {
            if (layout.Id == _activeLayoutId)
            {
                return layout.Name;
            }
        }

        return string.Empty;
    }

    private int GetActiveLayoutIndex()
    {
        for (var i = 0; i < _layouts.Count; i++)
        {
            if (_layouts[i].Id == _activeLayoutId)
            {
                return i;
            }
        }

        return -1;
    }

    private bool TryGetShapeValues(out (double X, double Y, double Z, double Width, double Height, double RotationDegrees) values)
    {
        values = default;
        if (!IsFinite(_ShapeXNumberBox.Value)
            || !IsFinite(_ShapeYNumberBox.Value)
            || !IsFinite(_ShapeZNumberBox.Value)
            || !IsFinite(_ShapeWidthNumberBox.Value)
            || !IsFinite(_ShapeHeightNumberBox.Value)
            || !IsFinite(_ShapeRotationNumberBox.Value))
        {
            return false;
        }

        values = (
            RoundTo2(_ShapeXNumberBox.Value),
            RoundTo2(_ShapeYNumberBox.Value),
            RoundTo2(_ShapeZNumberBox.Value),
            RoundTo2(_ShapeWidthNumberBox.Value),
            RoundTo2(_ShapeHeightNumberBox.Value),
            RoundTo2(_ShapeRotationNumberBox.Value));
        return true;
    }

    private bool TryGetLineValues(out (double StartX, double StartY, double StartZ, double EndX, double EndY, double EndZ, double Thickness) values)
    {
        values = default;
        if (!IsFinite(_LineStartXNumberBox.Value)
            || !IsFinite(_LineStartYNumberBox.Value)
            || !IsFinite(_LineStartZNumberBox.Value)
            || !IsFinite(_LineEndXNumberBox.Value)
            || !IsFinite(_LineEndYNumberBox.Value)
            || !IsFinite(_LineEndZNumberBox.Value)
            || !IsFinite(_LineThicknessNumberBox.Value))
        {
            return false;
        }

        values = (
            RoundTo2(_LineStartXNumberBox.Value),
            RoundTo2(_LineStartYNumberBox.Value),
            RoundTo2(_LineStartZNumberBox.Value),
            RoundTo2(_LineEndXNumberBox.Value),
            RoundTo2(_LineEndYNumberBox.Value),
            RoundTo2(_LineEndZNumberBox.Value),
            RoundTo2(_LineThicknessNumberBox.Value));
        return true;
    }

    private static bool TryParseAlignment(object? value, out SceneCanvas.SelectionAlignment alignment)
    {
        alignment = SceneCanvas.SelectionAlignment.Left;
        if (value == null)
        {
            return false;
        }

        return Enum.TryParse(value.ToString(), ignoreCase: true, out alignment);
    }

    private static bool TryParseLayout(object? value, out SceneCanvas.SelectionLayout layout)
    {
        layout = SceneCanvas.SelectionLayout.PackLeftToRight;
        if (value == null)
        {
            return false;
        }

        return Enum.TryParse(value.ToString(), ignoreCase: true, out layout);
    }

    private static bool IsFinite(double value)
    {
        return !double.IsNaN(value) && !double.IsInfinity(value);
    }

    private static void SetFieldValueIfChanged(ToolBarNumberField? field, double value)
    {
        if (field == null || !double.IsFinite(value))
        {
            return;
        }

        if (Math.Abs(field.Value - value) < 0.00001d)
        {
            return;
        }

        field.Value = value;
    }

    private bool TryGetMoveDeltaValues(out (double DeltaX, double DeltaY) values)
    {
        values = default;
        if (_MoveDeltaXNumberBox == null
            || _MoveDeltaYNumberBox == null
            || !IsFinite(_MoveDeltaXNumberBox.Value)
            || !IsFinite(_MoveDeltaYNumberBox.Value))
        {
            return false;
        }

        values = (
            RoundTo2(_MoveDeltaXNumberBox.Value),
            RoundTo2(_MoveDeltaYNumberBox.Value));
        return true;
    }

    private static double RoundTo2(double value)
    {
        return Math.Round(value, 2, MidpointRounding.AwayFromZero);
    }

    private void UpdateEditingControlsState()
    {
        var canEdit = _isEditModeEnabled && !_isRulerModeEnabled;
        var hasSelection = _selectedCount > 0;
        var hasMultiSelection = _selectedCount > 1;

        SetGroupEditableState(_EditGroup, true);
        SetGroupEditableState(_ToolsGroup, true);
        SetGroupEditableState(_ViewGroup, true);
        SetGroupEditableState(_AlignGroup, canEdit && hasMultiSelection);
        SetGroupEditableState(_ArrangeGroup, canEdit && hasMultiSelection);
        SetGroupEditableState(_TransformGroup, canEdit && hasSelection);
        SetGroupEditableState(_MoveGroup, canEdit && hasSelection);
        SetGroupEditableState(_LayoutsGroup, true);
        SetGroupEditableState(_ShapePropertiesGroup, canEdit);
        SetGroupEditableState(_LinePropertiesGroup, canEdit);
        RefreshLayoutControls();
        RefreshActionControls();
    }

    private void RefreshActionControls()
    {
        var canEdit = _isEditModeEnabled && !_isRulerModeEnabled;
        var hasSelection = _selectedCount > 0;
        var hasMultiSelection = _selectedCount > 1;

        SetControlEnabled(_EditCutButton, canEdit && hasSelection);
        SetControlEnabled(_EditCopyButton, hasSelection);
        SetControlEnabled(_EditPasteButton, canEdit);
        SetControlEnabled(_EditDeleteButton, canEdit && hasSelection);
        SetControlEnabled(_EditCloneButton, canEdit && hasSelection);
        SetControlEnabled(_EditUndoButton, canEdit);

        SetControlEnabled(_ZoomInButton, true);
        SetControlEnabled(_ZoomOutButton, true);
        SetControlEnabled(_FitToObjectsButton, true);
        SetControlEnabled(_ZoomToSelectionButton, hasSelection);
        SetControlEnabled(_GridVisibilityToggleButton, true);
        SetControlEnabled(_RulersVisibilityToggleButton, true);

        SetControlEnabled(_BringToFrontButton, canEdit && hasSelection);
        SetControlEnabled(_SendToBackButton, canEdit && hasSelection);
        SetControlEnabled(_AddVerticalGuideButton, canEdit);
        SetControlEnabled(_AddHorizontalGuideButton, canEdit);
        SetControlEnabled(_MagnetSplitButton, true);

        SetControlEnabled(_MatchSelectionWidthButton, canEdit && hasMultiSelection);
        SetControlEnabled(_MatchSelectionHeightButton, canEdit && hasMultiSelection);
        SetControlEnabled(_RotateSelectionLeftButton, canEdit && hasSelection);
        SetControlEnabled(_RotateSelectionRightButton, canEdit && hasSelection);

        SetControlEnabled(_ApplyMoveDeltaButton, canEdit && hasSelection);
        SetElementEnabled(_MoveDeltaXNumberBox, canEdit && hasSelection);
        SetElementEnabled(_MoveDeltaYNumberBox, canEdit && hasSelection);
    }

    private static void SetGroupEditableState(FrameworkElement element, bool isEnabled)
    {
        if (element == null)
        {
            return;
        }

        element.IsHitTestVisible = isEnabled;
        element.Opacity = isEnabled ? 1d : 0.55d;
    }

    private static void SetControlEnabled(Control? control, bool isEnabled)
    {
        if (control == null)
        {
            return;
        }

        control.IsEnabled = isEnabled;
    }

    private static void SetElementEnabled(FrameworkElement? element, bool isEnabled)
    {
        if (element == null)
        {
            return;
        }

        element.IsHitTestVisible = isEnabled;
        element.Opacity = isEnabled ? 1d : 0.55d;
    }
}
