using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using TraceCad.App.Tools;
using TraceCad.Core.Commands;
using TraceCad.Core.Model;
using TraceCad.Core.Serialization;
using TraceCad.Core.Validation;
using TraceCad.Dxf;
using TraceCad.Vision.Calibration;

namespace TraceCad.App;

public sealed class MainWindow : Window
{
    private static readonly SolidColorBrush AppBackground = Brush("#0b1020");
    private static readonly SolidColorBrush ChromeBackground = Brush("#111827");
    private static readonly SolidColorBrush GlassBackground = Brush("#0f172a");
    private static readonly SolidColorBrush PanelBackground = Brush("#111827");
    private static readonly SolidColorBrush RailBackground = Brush("#0f172a");
    private static readonly SolidColorBrush RailButtonBackground = Brush("#1f2937");
    private static readonly SolidColorBrush RailButtonSelectedBackground = Brush("#1d4ed8");
    private static readonly SolidColorBrush StrokeBrush = Brush("#334155");
    private static readonly SolidColorBrush GlassStroke = Brush("#475569");
    private static readonly SolidColorBrush TextPrimary = Brush("#f8fafc");
    private static readonly SolidColorBrush TextSecondary = Brush("#cbd5e1");
    private static readonly SolidColorBrush TextMuted = Brush("#94a3b8");
    private static readonly SolidColorBrush TextOnDark = Brush("#ffffff");
    private static readonly SolidColorBrush Accent = Brush("#3b82f6");
    private static readonly SolidColorBrush AccentSoft = Brush("#172554");

    private readonly SketchCanvas _canvas = new();
    private readonly TextBlock _status = Text("", TextSecondary, 12);
    private readonly TextBlock _toolState = Text("", TextSecondary, 12);
    private readonly TextBlock _referenceName = Text("", TextSecondary, 12);
    private readonly TextBlock _calibrationSummary = Text("No calibration data.", TextSecondary, 12);
    private readonly TextBlock _constraintSummary = Text("", TextSecondary, 12);
    private readonly TextBlock _validationSummary = Text("", TextSecondary, 12);
    private readonly NumericUpDown _dimensionValue = NumberInput(0.1, minimum: 0.0001);
    private readonly Button _dimensionApplyButton;
    private readonly Slider _referenceOpacity = new() { Minimum = 0.0, Maximum = 1.0, Value = 0.55 };
    private readonly CheckBox _referenceLocked = new() { Content = "Locked", Foreground = TextPrimary };
    private readonly NumericUpDown _referenceX = NumberInput(1.0);
    private readonly NumericUpDown _referenceY = NumberInput(1.0);
    private readonly NumericUpDown _referenceScale = NumberInput(0.01, minimum: 0.0001);
    private readonly NumericUpDown _referenceRotation = NumberInput(1.0, minimum: -3600.0, maximum: 3600.0);
    private readonly Button _calibrationMeasureButton;
    private readonly Button _calibrationCorrectionButton;
    private readonly IDxfExporter _dxfExporter = new NetDxfExporter();
    private readonly SheetCalibrator _sheetCalibrator = new();
    private readonly Dictionary<string, (Button Button, string Icon)> _toolButtons = new();
    private bool _syncingReferencePanel;

    public MainWindow()
    {
        Title = "easyTrace";
        Width = 1360;
        Height = 860;
        MinWidth = 980;
        MinHeight = 640;
        Background = AppBackground;
        TransparencyLevelHint = new[] { WindowTransparencyLevel.None };
        TransparencyBackgroundFallback = AppBackground;
        _calibrationMeasureButton = CommandButton(
            UiIcon.Measure,
            "Select 30 mm Line",
            (_, _) => BeginManualCalibrationMeasurement());
        _calibrationCorrectionButton = CommandButton(
            UiIcon.Apply,
            "Apply 30 mm Correction",
            (_, _) => ApplyCalibrationScaleCorrection());
        _dimensionApplyButton = CommandButton(
            UiIcon.Apply,
            "Apply Latest Dimension",
            (_, _) => ApplyLatestDimensionValue());

        _referenceOpacity.PropertyChanged += (_, e) =>
        {
            if (_syncingReferencePanel || e.Property != RangeBase.ValueProperty)
            {
                return;
            }

            _canvas.SetReferenceOpacity(_referenceOpacity.Value);
            UpdateStatus();
        };
        _referenceLocked.PropertyChanged += (_, e) =>
        {
            if (_syncingReferencePanel || e.Property != ToggleButton.IsCheckedProperty)
            {
                return;
            }

            SetReferenceLockedFromPanel();
        };

        Content = BuildLayout();
        _canvas.StatusChanged += (_, _) => UpdateStatus();
        _canvas.Changed += (_, _) =>
        {
            UpdateStatus();
            SyncReferencePanel();
            SyncCalibrationSummary();
            SyncConstraintSummary();
            SyncValidationSummary();
            ApplyToolButtonState();
        };
        UpdateStatus();
        SyncReferencePanel();
        SyncCalibrationSummary();
        SyncConstraintSummary();
        SyncValidationSummary();
        ApplyToolButtonState();
    }

    private Control BuildLayout()
    {
        var root = new Grid
        {
            RowDefinitions = new RowDefinitions("76,*,34"),
            Background = AppSurfaceBrush()
        };

        var topBar = AddTopBar();
        Grid.SetRow(topBar, 0);
        root.Children.Add(topBar);

        var workArea = new Grid
        {
            ColumnDefinitions = new ColumnDefinitions("104,*,332"),
            Background = Brushes.Transparent
        };
        Grid.SetRow(workArea, 1);
        root.Children.Add(workArea);

        var rail = BuildToolRail();
        Grid.SetColumn(rail, 0);
        workArea.Children.Add(rail);

        var canvasHost = GlassPanel(
            _canvas,
            new Avalonia.Thickness(0, 10, 0, 14),
            new Avalonia.CornerRadius(12),
            GlassBackground);
        canvasHost.ClipToBounds = true;
        canvasHost.BorderThickness = new Avalonia.Thickness(1.4);
        Grid.SetColumn(canvasHost, 1);
        workArea.Children.Add(canvasHost);

        var inspector = BuildInspector();
        Grid.SetColumn(inspector, 2);
        workArea.Children.Add(inspector);

        var statusBar = BuildStatusBar();
        Grid.SetRow(statusBar, 2);
        root.Children.Add(statusBar);

        return root;
    }

    private Border GlassPanel(Control child, Avalonia.Thickness margin, Avalonia.CornerRadius cornerRadius, IBrush? background = null)
    {
        return new Border
        {
            Margin = margin,
            Background = background ?? GlassCardBrush(),
            BorderBrush = GlassStroke,
            BorderThickness = new Avalonia.Thickness(1),
            CornerRadius = cornerRadius,
            Child = child
        };
    }

    private Control AddTopBar()
    {
        var dock = new DockPanel
        {
            Margin = new Avalonia.Thickness(18, 11),
            LastChildFill = true
        };

        var brand = new StackPanel
        {
            Width = 205,
            Spacing = 0,
            VerticalAlignment = VerticalAlignment.Center
        };
        brand.Children.Add(Text("easyTrace", TextPrimary, 21, FontWeight.SemiBold));
        brand.Children.Add(Text("Calibrated 2D tracing CAD", TextMuted, 11));
        DockPanel.SetDock(brand, Dock.Left);
        dock.Children.Add(brand);

        var actions = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            VerticalAlignment = VerticalAlignment.Center
        };
        DockPanel.SetDock(actions, Dock.Right);
        actions.Children.Add(CommandButton(UiIcon.New, "New", (_, _) => NewDocument()));
        actions.Children.Add(CommandButton(UiIcon.Open, "Open", async (_, _) => await OpenProject()));
        actions.Children.Add(CommandButton(UiIcon.Save, "Save", async (_, _) => await SaveProject()));
        actions.Children.Add(CommandButton(UiIcon.Image, "Reference", async (_, _) => await ImportReference()));
        actions.Children.Add(CommandButton(UiIcon.Calibrate, "Calibrate", async (_, _) => await CalibrateSheet()));
        actions.Children.Add(PrimaryButton(UiIcon.Export, "Export DXF", async (_, _) => await ExportDxf()));
        dock.Children.Add(actions);

        var center = new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 8,
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center
        };
        center.Children.Add(CommandButton(UiIcon.Undo, "Undo", (_, _) => _canvas.Undo()));
        center.Children.Add(CommandButton(UiIcon.Redo, "Redo", (_, _) => _canvas.Redo()));
        center.Children.Add(CommandButton(UiIcon.Delete, "Delete", (_, _) => _canvas.DeleteSelected()));
        dock.Children.Add(center);

        return GlassPanel(
            dock,
            new Avalonia.Thickness(14, 12, 14, 6),
            new Avalonia.CornerRadius(14),
            ChromeBackground);
    }

    private Control BuildToolRail()
    {
        var stack = new StackPanel
        {
            Margin = new Avalonia.Thickness(12, 14),
            Spacing = 10
        };

        stack.Children.Add(Text("TOOLS", Brush("#94a3b8"), 10, FontWeight.SemiBold));
        stack.Children.Add(ToolButton(UiIcon.Select, "Select", () => _canvas.SelectTool()));
        stack.Children.Add(ToolButton(UiIcon.Line, "Line", () => _canvas.SetTool(new LineTool())));
        stack.Children.Add(ToolButton(UiIcon.Circle, "Circle 3P", () => _canvas.SetTool(new Circle3PointTool())));
        stack.Children.Add(ToolButton(UiIcon.Arc, "Arc 3P", () => _canvas.SetTool(new Arc3PointTool())));
        stack.Children.Add(ToolButton(UiIcon.Trim, "Trim", () => _canvas.SetTool(new TrimTool())));
        stack.Children.Add(ToolButton(UiIcon.Extend, "Extend", () => _canvas.SetTool(new ExtendTool())));
        stack.Children.Add(ToolButton(UiIcon.Measure, "Measure", () => _canvas.SetTool(new MeasureTool())));

        return GlassPanel(
            stack,
            new Avalonia.Thickness(14, 10, 12, 14),
            new Avalonia.CornerRadius(14),
            RailBackground);
    }

    private Control BuildInspector()
    {
        var panel = new StackPanel
        {
            Spacing = 14,
            Margin = new Avalonia.Thickness(18)
        };

        panel.Children.Add(SectionHeader("Reference Image"));
        panel.Children.Add(_referenceName);
        panel.Children.Add(LabeledControl("Opacity", _referenceOpacity));
        panel.Children.Add(_referenceLocked);
        panel.Children.Add(LabeledControl("X origin (mm)", _referenceX));
        panel.Children.Add(LabeledControl("Y origin (mm)", _referenceY));
        panel.Children.Add(LabeledControl("Scale (mm / image px)", _referenceScale));
        panel.Children.Add(LabeledControl("Rotation (deg)", _referenceRotation));
        panel.Children.Add(PrimaryButton(UiIcon.Apply, "Apply Transform", (_, _) => ApplyReferenceTransformFromPanel()));
        panel.Children.Add(CommandButton(UiIcon.Clear, "Clear Reference", (_, _) => _canvas.ClearReference()));
        panel.Children.Add(SectionHeader("Calibration"));
        panel.Children.Add(_calibrationSummary);
        panel.Children.Add(_calibrationMeasureButton);
        panel.Children.Add(_calibrationCorrectionButton);
        panel.Children.Add(new Border
        {
            Height = 1,
            Background = StrokeBrush,
            Margin = new Avalonia.Thickness(0, 4)
        });
        panel.Children.Add(SectionHeader("Document"));
        panel.Children.Add(DocumentMetric("Units", "mm"));
        panel.Children.Add(SectionHeader("Constraints"));
        panel.Children.Add(_constraintSummary);
        panel.Children.Add(CommandButton(UiIcon.Parallel, "Parallel", (_, _) => BeginConstraintTool(new ParallelConstraintTool())));
        panel.Children.Add(CommandButton(UiIcon.Tangent, "Tangent", (_, _) => BeginConstraintTool(new TangentConstraintTool())));
        panel.Children.Add(CommandButton(UiIcon.Measure, "Line Distance", (_, _) => BeginConstraintTool(new ParallelDistanceTool())));
        panel.Children.Add(CommandButton(UiIcon.Radius, "Arc Radius", (_, _) => BeginConstraintTool(new ArcRadiusTool())));
        panel.Children.Add(LabeledControl("Latest dimension (mm)", _dimensionValue));
        panel.Children.Add(_dimensionApplyButton);
        panel.Children.Add(SectionHeader("Alignment"));
        panel.Children.Add(CommandButton(UiIcon.Horizontal, "Align Horizontal", (_, _) => _canvas.AlignSelectedLineHorizontal()));
        panel.Children.Add(CommandButton(UiIcon.Vertical, "Align Vertical", (_, _) => _canvas.AlignSelectedLineVertical()));
        panel.Children.Add(SectionHeader("Drawing Health"));
        panel.Children.Add(_validationSummary);
        panel.Children.Add(CommandButton(UiIcon.Validate, "Check Drawing", (_, _) => RunDrawingHealthCheck()));

        var scroller = new ScrollViewer
        {
            Content = panel,
            VerticalScrollBarVisibility = ScrollBarVisibility.Auto
        };

        return GlassPanel(
            scroller,
            new Avalonia.Thickness(0, 10, 14, 14),
            new Avalonia.CornerRadius(14),
            PanelBackground);
    }

    private Control BuildStatusBar()
    {
        var dock = new DockPanel
        {
            Margin = new Avalonia.Thickness(14, 0),
            LastChildFill = true
        };
        DockPanel.SetDock(_toolState, Dock.Right);
        dock.Children.Add(_toolState);
        dock.Children.Add(_status);
        return GlassPanel(
            dock,
            new Avalonia.Thickness(14, 0, 14, 8),
            new Avalonia.CornerRadius(10),
            ChromeBackground);
    }

    private Button ToolButton(string icon, string text, Action action)
    {
        var button = new Button
        {
            Content = ToolButtonContent(icon, text, selected: false),
            Background = RailButtonBackground,
            Foreground = TextPrimary,
            BorderBrush = StrokeBrush,
            BorderThickness = new Avalonia.Thickness(1),
            Padding = new Avalonia.Thickness(5, 9),
            HorizontalAlignment = HorizontalAlignment.Stretch,
            HorizontalContentAlignment = HorizontalAlignment.Center,
            MinHeight = 66,
            CornerRadius = new Avalonia.CornerRadius(10)
        };
        button.Click += (_, _) =>
        {
            action();
            ApplyToolButtonState();
        };
        _toolButtons[text] = (button, icon);
        return button;
    }

    private static Button CommandButton(string icon, string text, EventHandler<RoutedEventArgs> handler)
    {
        var button = new Button
        {
            Content = CommandButtonContent(icon, text, TextPrimary),
            Background = Brush("#1f2937"),
            Foreground = TextPrimary,
            BorderBrush = StrokeBrush,
            BorderThickness = new Avalonia.Thickness(1),
            Padding = new Avalonia.Thickness(13, 8),
            MinHeight = 38,
            HorizontalContentAlignment = HorizontalAlignment.Center,
            CornerRadius = new Avalonia.CornerRadius(9)
        };
        button.Click += handler;
        return button;
    }

    private static Button PrimaryButton(string icon, string text, EventHandler<RoutedEventArgs> handler)
    {
        var button = CommandButton(icon, text, handler);
        button.Content = CommandButtonContent(icon, text, TextOnDark);
        button.Background = PrimaryAccentBrush();
        button.Foreground = TextOnDark;
        button.BorderBrush = Brush("#1d4ed8");
        return button;
    }

    private static Control LabeledControl(string label, Control input)
    {
        return new StackPanel
        {
            Spacing = 5,
            Children =
            {
                Text(label, TextSecondary, 11, FontWeight.SemiBold),
                input
            }
        };
    }

    private static Control DocumentMetric(string label, string value)
    {
        var grid = new Grid
        {
            ColumnDefinitions = new ColumnDefinitions("*,Auto")
        };
        var labelText = Text(label, TextSecondary, 12, FontWeight.SemiBold);
        var valueText = Text(value, TextPrimary, 12, FontWeight.SemiBold);
        Grid.SetColumn(valueText, 1);
        grid.Children.Add(labelText);
        grid.Children.Add(valueText);

        return new Border
        {
            Background = GlassCardBrush(),
            BorderBrush = Brush("#7fbfff44"),
            BorderThickness = new Avalonia.Thickness(1),
            CornerRadius = new Avalonia.CornerRadius(12),
            Padding = new Avalonia.Thickness(12, 9),
            Child = grid
        };
    }

    private static StackPanel CommandButtonContent(string icon, string text, IBrush foreground)
    {
        return new StackPanel
        {
            Orientation = Orientation.Horizontal,
            Spacing = 7,
            VerticalAlignment = VerticalAlignment.Center,
            Children =
            {
                IconText(icon, foreground, 14),
                Text(text, foreground, 12, FontWeight.SemiBold)
            }
        };
    }

    private static StackPanel ToolButtonContent(string icon, string text, bool selected)
    {
        var foreground = selected ? Accent : TextSecondary;
        return new StackPanel
        {
            Spacing = 5,
            HorizontalAlignment = HorizontalAlignment.Center,
            Children =
            {
                IconText(icon, foreground, 22),
                Text(text, foreground, 10, FontWeight.SemiBold)
            }
        };
    }

    private static TextBlock IconText(string glyph, IBrush foreground, double size) =>
        new()
        {
            Text = glyph,
            FontFamily = new FontFamily("Segoe MDL2 Assets"),
            Foreground = foreground,
            FontSize = size,
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center
        };

    private static TextBlock SectionHeader(string text) =>
        Text(text, TextPrimary, 15, FontWeight.SemiBold);

    private static TextBlock Text(string text, IBrush foreground, double size, FontWeight weight = FontWeight.Normal) =>
        new()
        {
            Text = text,
            Foreground = foreground,
            FontSize = size,
            FontWeight = weight,
            TextWrapping = TextWrapping.Wrap
        };

    private void NewDocument()
    {
        _canvas.SetDocument(SketchDocument.CreateDefault());
        UpdateStatus("New project");
    }

    private async Task ImportReference()
    {
        var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
        {
            AllowMultiple = false,
            Title = "Import reference image",
            FileTypeFilter = new[] { ImageFileType }
        });

        var path = files.FirstOrDefault()?.TryGetLocalPath();
        if (path is null)
        {
            return;
        }

        _canvas.ImportReferenceImage(path);
        SyncReferencePanel();
    }

    private async Task CalibrateSheet()
    {
        var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
        {
            AllowMultiple = false,
            Title = "Calibrate reference sheet photo",
            FileTypeFilter = new[] { ImageFileType }
        });

        var path = files.FirstOrDefault()?.TryGetLocalPath();
        if (path is null)
        {
            return;
        }

        UpdateStatus("Calibrating reference sheet...");

        try
        {
            var outputDirectory = Path.Combine(
                Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
                "easyTrace",
                "calibrated-references");
            var result = await Task.Run(() => _sheetCalibrator.Calibrate(path, outputDirectory));
            if (!result.Success || result.CorrectedImagePath is null)
            {
                UpdateStatus(result.Message);
                return;
            }

            _canvas.SetReferenceImage(new ReferenceImage(
                result.CorrectedImagePath,
                0.55,
                Locked: true,
                new ReferenceTransform(
                    OriginX: 0.0,
                    OriginY: 0.0,
                    ScaleX: result.MmPerPixel,
                    ScaleY: result.MmPerPixel,
                    RotationDeg: 0.0)));
            SyncReferencePanel();
            SyncCalibrationSummary();
            UpdateStatus(result.Message);
        }
        catch (Exception ex)
        {
            UpdateStatus($"Calibration failed: {ex.Message}");
        }
    }

    private async Task OpenProject()
    {
        var files = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
        {
            AllowMultiple = false,
            Title = "Open easyTrace project",
            FileTypeFilter = new[] { ProjectFileType }
        });

        var path = files.FirstOrDefault()?.TryGetLocalPath();
        if (path is null)
        {
            return;
        }

        var json = await File.ReadAllTextAsync(path);
        _canvas.SetDocument(SketchDocumentSerializer.Deserialize(json));
        UpdateStatus($"Opened {Path.GetFileName(path)}");
    }

    private async Task SaveProject()
    {
        var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
        {
            Title = "Save easyTrace project",
            SuggestedFileName = "drawing.easytrace.json",
            FileTypeChoices = new[] { ProjectFileType }
        });

        var path = file?.TryGetLocalPath();
        if (path is null)
        {
            return;
        }

        await File.WriteAllTextAsync(path, SketchDocumentSerializer.Serialize(_canvas.Document));
        UpdateStatus($"Saved {Path.GetFileName(path)}");
    }

    private async Task ExportDxf()
    {
        var issues = DrawingValidator.Validate(_canvas.Document);
        var errors = issues.Where(issue => issue.Severity == DrawingIssueSeverity.Error).ToList();
        if (errors.Count > 0)
        {
            UpdateStatus($"Export blocked: {errors[0].Message}");
            SyncValidationSummary();
            return;
        }

        var file = await StorageProvider.SaveFilePickerAsync(new FilePickerSaveOptions
        {
            Title = "Export DXF",
            SuggestedFileName = "drawing.dxf",
            FileTypeChoices = new[] { DxfFileType }
        });

        var path = file?.TryGetLocalPath();
        if (path is null)
        {
            return;
        }

        _dxfExporter.Export(_canvas.Document, path);
        var warningCount = issues.Count(issue => issue.Severity == DrawingIssueSeverity.Warning);
        UpdateStatus(warningCount == 0
            ? $"Exported {Path.GetFileName(path)}"
            : $"Exported {Path.GetFileName(path)} with {warningCount} warning(s)");
    }

    private void UpdateStatus(string? prefix = null)
    {
        _status.Text = prefix ?? _canvas.StatusText;
        var reference = _canvas.Document.Reference is null ? "No reference" : "Reference loaded";
        _toolState.Text = $"Tool: {_canvas.ActiveToolName}   Entities: {_canvas.Document.Entities.Count}   Constraints: {_canvas.Document.Constraints.Count}   {reference}";
    }

    private void SyncReferencePanel()
    {
        _syncingReferencePanel = true;

        var reference = _canvas.Document.Reference;
        var hasReference = reference is not null;
        _referenceName.Text = hasReference ? Path.GetFileName(reference!.ImagePath) : "No image imported";
        _referenceOpacity.IsEnabled = hasReference;
        _referenceLocked.IsEnabled = hasReference;
        _referenceX.IsEnabled = hasReference && !reference!.Locked;
        _referenceY.IsEnabled = hasReference && !reference!.Locked;
        _referenceScale.IsEnabled = hasReference && !reference!.Locked;
        _referenceRotation.IsEnabled = hasReference && !reference!.Locked;

        if (reference is not null)
        {
            _referenceOpacity.Value = reference.Opacity;
            _referenceLocked.IsChecked = reference.Locked;
            _referenceX.Value = (decimal)reference.Transform.OriginX;
            _referenceY.Value = (decimal)reference.Transform.OriginY;
            _referenceScale.Value = (decimal)reference.Transform.ScaleX;
            _referenceRotation.Value = (decimal)reference.Transform.RotationDeg;
        }
        else
        {
            _referenceLocked.IsChecked = false;
            _referenceX.Value = 0m;
            _referenceY.Value = 0m;
            _referenceScale.Value = 1m;
            _referenceRotation.Value = 0m;
        }

        _syncingReferencePanel = false;
    }

    private void SyncCalibrationSummary()
    {
        var calibration = _canvas.Document.Reference?.Calibration;
        if (calibration is null)
        {
            _calibrationSummary.Text = _canvas.Document.Reference is null
                ? "No calibration data."
                : "Select the bold 30 mm line to estimate accuracy.";
            _calibrationSummary.Foreground = TextSecondary;
            _calibrationMeasureButton.IsEnabled = _canvas.Document.Reference is not null;
            _calibrationMeasureButton.IsVisible = _canvas.Document.Reference is not null;
            _calibrationCorrectionButton.IsEnabled = false;
            _calibrationCorrectionButton.IsVisible = false;
            return;
        }

        if (!calibration.ControlLineDetected)
        {
            _calibrationSummary.Text = "30 mm control line not detected.";
            _calibrationSummary.Foreground = Brush("#fde68a");
            _calibrationMeasureButton.IsEnabled = _canvas.Document.Reference is not null;
            _calibrationMeasureButton.IsVisible = _canvas.Document.Reference is not null;
            _calibrationCorrectionButton.IsEnabled = false;
            _calibrationCorrectionButton.IsVisible = false;
            return;
        }

        _calibrationSummary.Text =
            $"Estimated accuracy: +/-{calibration.EstimatedAccuracyMm:0.###} mm\n" +
            $"30 mm line: {calibration.MeasuredLineLengthMm:0.###} mm ({calibration.ErrorMm:+0.###;-0.###;0} mm)";
        _calibrationSummary.Foreground = calibration.MeetsTargetAccuracy ? TextSecondary : Brush("#fde68a");
        _calibrationMeasureButton.IsVisible = true;
        _calibrationMeasureButton.IsEnabled = _canvas.Document.Reference is not null;
        _calibrationCorrectionButton.IsVisible = !calibration.MeetsTargetAccuracy;
        _calibrationCorrectionButton.IsEnabled = !calibration.MeetsTargetAccuracy;
    }

    private void SyncValidationSummary()
    {
        var issues = DrawingValidator.Validate(_canvas.Document);
        var errorCount = issues.Count(issue => issue.Severity == DrawingIssueSeverity.Error);
        var warningCount = issues.Count(issue => issue.Severity == DrawingIssueSeverity.Warning);

        if (issues.Count == 0)
        {
            _validationSummary.Text = "No issues found.";
            _validationSummary.Foreground = TextSecondary;
            return;
        }

        var first = issues[0];
        _validationSummary.Text = $"{errorCount} error(s), {warningCount} warning(s). {first.Message}";
        _validationSummary.Foreground = errorCount > 0 ? Brush("#fca5a5") : Brush("#fde68a");
    }

    private void SyncConstraintSummary()
    {
        var constraints = _canvas.Document.Constraints;
        if (constraints.Count == 0)
        {
            _constraintSummary.Text = "No constraints or measurements.";
            _constraintSummary.Foreground = TextSecondary;
            _dimensionValue.IsEnabled = false;
            _dimensionApplyButton.IsEnabled = false;
            _dimensionApplyButton.IsVisible = false;
            return;
        }

        var geometricCount = constraints.Count(constraint =>
            constraint.Type is ConstraintType.Parallel or ConstraintType.Tangent or ConstraintType.Colinear or ConstraintType.Horizontal or ConstraintType.Vertical);
        var measurementCount = constraints.Count(constraint =>
            constraint.Type is ConstraintType.Distance or ConstraintType.Radius);
        var latest = constraints
            .TakeLast(3)
            .Reverse()
            .Select(FormatConstraint)
            .ToArray();

        _constraintSummary.Text =
            $"{geometricCount} constraint(s), {measurementCount} measurement(s)\n" +
            string.Join('\n', latest);
        _constraintSummary.Foreground = TextSecondary;

        var latestMeasurement = LatestDimensionConstraint();
        _dimensionValue.IsEnabled = latestMeasurement is not null;
        _dimensionApplyButton.IsVisible = latestMeasurement is not null;
        _dimensionApplyButton.IsEnabled = latestMeasurement is not null;
        if (latestMeasurement?.ValueMm is { } value)
        {
            _dimensionValue.Value = (decimal)Math.Abs(value);
        }
    }

    private void RunDrawingHealthCheck()
    {
        SyncValidationSummary();

        var issues = DrawingValidator.Validate(_canvas.Document);
        if (issues.Count == 0)
        {
            UpdateStatus("Drawing health: no issues found");
            return;
        }

        var errorCount = issues.Count(issue => issue.Severity == DrawingIssueSeverity.Error);
        var warningCount = issues.Count(issue => issue.Severity == DrawingIssueSeverity.Warning);
        UpdateStatus($"Drawing health: {errorCount} error(s), {warningCount} warning(s) - {issues[0].Message}");
    }

    private void SetReferenceLockedFromPanel()
    {
        if (_syncingReferencePanel)
        {
            return;
        }

        _canvas.SetReferenceLocked(_referenceLocked.IsChecked == true);
        SyncReferencePanel();
    }

    private void ApplyReferenceTransformFromPanel()
    {
        if (_canvas.Document.Reference is null || _canvas.Document.Reference.Locked)
        {
            return;
        }

        var scale = ToDouble(_referenceScale.Value, 1.0);
        _canvas.SetReferenceTransform(new ReferenceTransform(
            ToDouble(_referenceX.Value, 0.0),
            ToDouble(_referenceY.Value, 0.0),
            scale,
            scale,
            ToDouble(_referenceRotation.Value, 0.0)));
        SyncReferencePanel();
    }

    private void ApplyCalibrationScaleCorrection()
    {
        var reference = _canvas.Document.Reference;
        var calibration = reference?.Calibration;
        if (reference is null ||
            calibration is null ||
            !calibration.ControlLineDetected ||
            calibration.MeetsTargetAccuracy)
        {
            return;
        }

        var factor = calibration.ScaleCorrectionFactor;
        var corrected = reference with
        {
            Transform = reference.Transform with
            {
                ScaleX = reference.Transform.ScaleX * factor,
                ScaleY = reference.Transform.ScaleY * factor
            },
            Calibration = calibration with
            {
                MeasuredLineLengthMm = calibration.TargetLineLengthMm,
                ErrorMm = 0.0,
                EstimatedAccuracyMm = 0.0,
                ScaleCorrectionFactor = 1.0,
                MeetsTargetAccuracy = true
            }
        };

        _canvas.SetReferenceImage(corrected);
        SyncReferencePanel();
        SyncCalibrationSummary();
        UpdateStatus("Applied 30 mm calibration scale correction");
    }

    private void BeginManualCalibrationMeasurement()
    {
        if (_canvas.Document.Reference is null)
        {
            UpdateStatus("Import or calibrate a reference image first");
            return;
        }

        _canvas.SetTool(new CalibrationLineTool(ApplyManualCalibrationMeasurement));
        ApplyToolButtonState();
        UpdateStatus("30 mm Calibration: click both ends of the bold 30 mm line");
    }

    private void BeginConstraintTool(ISketchTool tool)
    {
        _canvas.SetTool(tool);
        ApplyToolButtonState();
        UpdateStatus(tool.Prompt);
    }

    private void ApplyLatestDimensionValue()
    {
        var constraint = LatestDimensionConstraint();
        if (constraint is null)
        {
            UpdateStatus("No dimension measurement selected");
            return;
        }

        var value = Math.Max(0.0001, ToDouble(_dimensionValue.Value, Math.Abs(constraint.ValueMm ?? 1.0)));
        var signedValue = constraint.Type == ConstraintType.Distance && constraint.ValueMm < 0.0
            ? -value
            : value;
        var replacement = constraint with { ValueMm = signedValue };
        _canvas.Commands.Execute(_canvas.Document, new UpdateConstraintCommand(constraint, replacement));
        SyncConstraintSummary();
        UpdateStatus($"{FormatConstraint(replacement)} applied");
    }

    private void ApplyManualCalibrationMeasurement(TraceCad.Core.Geometry.Point2 start, TraceCad.Core.Geometry.Point2 end)
    {
        var reference = _canvas.Document.Reference;
        if (reference is null)
        {
            return;
        }

        const double targetLineLengthMm = 30.0;
        const double targetAccuracyMm = 0.1;
        var measured = start.DistanceTo(end);
        if (measured <= 0.0001)
        {
            UpdateStatus("30 mm Calibration: selected line is too short");
            return;
        }

        var error = measured - targetLineLengthMm;
        var calibration = new ReferenceCalibration(
            TargetLineLengthMm: targetLineLengthMm,
            MeasuredLineLengthMm: measured,
            ErrorMm: error,
            EstimatedAccuracyMm: Math.Abs(error),
            ScaleCorrectionFactor: targetLineLengthMm / measured,
            MeetsTargetAccuracy: Math.Abs(error) <= targetAccuracyMm,
            ControlLineDetected: true);

        _canvas.SetReferenceImage(reference with { Calibration = calibration });
        SyncReferencePanel();
        SyncCalibrationSummary();
        UpdateStatus(calibration.MeetsTargetAccuracy
            ? $"30 mm Calibration: measured {measured:0.###} mm, target met"
            : $"30 mm Calibration: measured {measured:0.###} mm, correction available");
    }

    private void ApplyToolButtonState()
    {
        foreach (var (name, entry) in _toolButtons)
        {
            var selected = string.Equals(name, _canvas.ActiveToolName, StringComparison.Ordinal);
            entry.Button.Background = selected ? RailButtonSelectedBackground : RailButtonBackground;
            entry.Button.BorderBrush = selected ? Brush("#93c5fd") : StrokeBrush;
            entry.Button.Content = ToolButtonContent(entry.Icon, name, selected);
        }
    }

    private static double ToDouble(decimal? value, double fallback) =>
        value is null ? fallback : (double)value.Value;

    private SketchConstraint? LatestDimensionConstraint() =>
        _canvas.Document.Constraints
            .LastOrDefault(constraint => constraint.Type is ConstraintType.Distance or ConstraintType.Radius);

    private static string FormatConstraint(SketchConstraint constraint)
    {
        return constraint.Type switch
        {
            ConstraintType.Parallel => "Parallel",
            ConstraintType.Tangent => "Tangent",
            ConstraintType.Distance when constraint.ValueMm is not null =>
                $"Distance {Math.Abs(constraint.ValueMm.Value):0.###} mm",
            ConstraintType.Radius when constraint.ValueMm is not null =>
                $"Radius {constraint.ValueMm.Value:0.###} mm",
            ConstraintType.Horizontal => "Horizontal",
            ConstraintType.Vertical => "Vertical",
            ConstraintType.Colinear => "Colinear",
            _ => constraint.Type.ToString()
        };
    }

    private static NumericUpDown NumberInput(double increment, double minimum = -100000.0, double maximum = 100000.0) =>
        new()
        {
            Minimum = (decimal)minimum,
            Maximum = (decimal)maximum,
            Increment = (decimal)increment,
            FormatString = "0.####",
            HorizontalAlignment = HorizontalAlignment.Stretch,
            Background = Brush("#0f172a"),
            Foreground = TextPrimary,
            BorderBrush = StrokeBrush,
            BorderThickness = new Avalonia.Thickness(1),
            CornerRadius = new Avalonia.CornerRadius(7)
        };

    private static IBrush AppSurfaceBrush() =>
        new LinearGradientBrush
        {
            StartPoint = new Avalonia.RelativePoint(0.0, 0.0, Avalonia.RelativeUnit.Relative),
            EndPoint = new Avalonia.RelativePoint(1.0, 1.0, Avalonia.RelativeUnit.Relative),
            GradientStops =
            {
                new GradientStop(Color.Parse("#0b1020"), 0.0),
                new GradientStop(Color.Parse("#111827"), 0.52),
                new GradientStop(Color.Parse("#0f172a"), 1.0)
            }
        };

    private static IBrush PrimaryAccentBrush() =>
        new LinearGradientBrush
        {
            StartPoint = new Avalonia.RelativePoint(0.0, 0.0, Avalonia.RelativeUnit.Relative),
            EndPoint = new Avalonia.RelativePoint(1.0, 1.0, Avalonia.RelativeUnit.Relative),
            GradientStops =
            {
                new GradientStop(Color.Parse("#60a5fa"), 0.0),
                new GradientStop(Color.Parse("#3b82f6"), 0.5),
                new GradientStop(Color.Parse("#1d4ed8"), 1.0)
            }
        };

    private static IBrush GlassCardBrush() =>
        new LinearGradientBrush
        {
            StartPoint = new Avalonia.RelativePoint(0.0, 0.0, Avalonia.RelativeUnit.Relative),
            EndPoint = new Avalonia.RelativePoint(1.0, 1.0, Avalonia.RelativeUnit.Relative),
            GradientStops =
            {
                new GradientStop(Color.Parse("#1e293b"), 0.0),
                new GradientStop(Color.Parse("#111827"), 0.55),
                new GradientStop(Color.Parse("#0f172a"), 1.0)
            }
        };

    private static SolidColorBrush Brush(string color) => new(Color.Parse(color));

    private static class UiIcon
    {
        public const string New = "\uE710";
        public const string Open = "\uE838";
        public const string Save = "\uE74E";
        public const string Image = "\uE91B";
        public const string Calibrate = "\uE9F9";
        public const string Export = "\uE898";
        public const string Undo = "\uE7A7";
        public const string Redo = "\uE7A6";
        public const string Delete = "\uE74D";
        public const string Select = "\uE7C9";
        public const string Line = "\uE738";
        public const string Circle = "\uEA3A";
        public const string Arc = "\uE7C1";
        public const string Trim = "\uE8C6";
        public const string Extend = "\uE8E3";
        public const string Measure = "\uE9D9";
        public const string Horizontal = "\uE76F";
        public const string Vertical = "\uE784";
        public const string Parallel = "\uE8AB";
        public const string Tangent = "\uE9CB";
        public const string Radius = "\uE9CE";
        public const string Apply = "\uE73E";
        public const string Clear = "\uE711";
        public const string Validate = "\uE9D2";
    }

    private static FilePickerFileType ProjectFileType { get; } = new("easyTrace project")
    {
        Patterns = new[] { "*.easytrace.json", "*.tracecad.json", "*.json" }
    };

    private static FilePickerFileType DxfFileType { get; } = new("DXF")
    {
        Patterns = new[] { "*.dxf" }
    };

    private static FilePickerFileType ImageFileType { get; } = new("Images")
    {
        Patterns = new[] { "*.png", "*.jpg", "*.jpeg", "*.bmp", "*.tif", "*.tiff", "*.webp" }
    };

    protected override void OnKeyDown(KeyEventArgs e)
    {
        base.OnKeyDown(e);

        if (!e.KeyModifiers.HasFlag(KeyModifiers.Control))
        {
            return;
        }

        if (e.Key == Key.S)
        {
            _ = SaveProject();
            e.Handled = true;
        }
    }
}
