@namespace Lumeo

<Chart Option="@_option" Width="@Width" Height="@Height" Theme="@Theme" Class="@Class" IsLoading="@IsLoading" ShowLoadingSkeleton="@ShowLoadingSkeleton" SkeletonKind="@SkeletonKind" SkeletonStyle="@SkeletonStyle" ShowLoadingLabel="@ShowLoadingLabel" LoadingText="@LoadingText" PhantomCycleMs="@PhantomCycleMs" @attributes="AdditionalAttributes" />

@code {
    [Parameter] public double Value { get; set; }
    [Parameter] public double Min { get; set; } = 0;
    [Parameter] public double Max { get; set; } = 100;
    [Parameter] public string? Title { get; set; }
    [Parameter] public string? Unit { get; set; }
    [Parameter] public bool ShowPointer { get; set; } = true;
    [Parameter] public List<GaugeRange>? Ranges { get; set; }
    [Parameter] public string Width { get; set; } = "100%";
    [Parameter] public string Height { get; set; } = "350px";
    [Parameter] public string? Theme { get; set; }
    [Parameter] public string? Class { get; set; }
    [Parameter(CaptureUnmatchedValues = true)] public Dictionary<string, object>? AdditionalAttributes { get; set; }
    /// <summary>When true, overlays a shape-aware loading skeleton on top of the chart (consumer is fetching data). Flips back to the real chart once set to false.</summary>
    [Parameter] public bool IsLoading { get; set; }
    /// <summary>When true (default), renders a shape-aware skeleton while the chart has not yet mounted and whenever <see cref="IsLoading"/> is true. Set to <c>false</c> to opt out.</summary>
    [Parameter] public bool ShowLoadingSkeleton { get; set; } = true;
    /// <summary>Shape family for the loading skeleton. Defaults to <c>ChartSkeletonKind.Gauge</c> for this chart type; override if you want a different silhouette.</summary>
    [Parameter] public ChartSkeletonKind SkeletonKind { get; set; } = ChartSkeletonKind.Gauge;
    /// <summary>Phantom (default) renders the real chart with placeholder data and morphs to real data via ECharts' option-change animation. Silhouette falls back to the legacy SVG skeleton overlay.</summary>
    [Parameter] public ChartSkeletonStyle SkeletonStyle { get; set; } = ChartSkeletonStyle.Phantom;
    /// <summary>Phantom-mode refresh interval in milliseconds. Lower = faster data cycling while loading. Defaults to 1400.</summary>
    [Parameter] public int PhantomCycleMs { get; set; } = 1400;
    /// <summary>When true (default), shows a small "Loading…" pill in the top-right corner whenever <see cref="IsLoading"/> is active. Works on top of any <see cref="SkeletonStyle"/>.</summary>
    [Parameter] public bool ShowLoadingLabel { get; set; } = true;
    /// <summary>Label rendered next to the spinner inside the loading pill. Set to empty to hide. Defaults to "Loading…".</summary>
    [Parameter] public string? LoadingText { get; set; } = "Loading…";

    [Parameter] public bool ShowDataLabels { get; set; }
    [Parameter] public string LabelPosition { get; set; } = "top";
    [Parameter] public string? LabelFormat { get; set; }
    [Parameter] public bool DataZoom { get; set; }
    [Parameter] public bool Toolbox { get; set; }
    [Parameter] public List<string>? ColorPalette { get; set; }
    [Parameter] public int? AnimationDuration { get; set; }
    [Parameter] public string? AnimationEasing { get; set; }
    [Parameter] public Dictionary<string, object>? OptionOverride { get; set; }

    private EChartOption _option = new();

    protected override void OnParametersSet()
    {
        var formatter = Unit is not null ? $"{{value}} {Unit}" : "{value}";

        var series = new EChartSeries
        {
            Type = "gauge",
            Min = Min,
            Max = Max,
            Pointer = new EChartPointer { Show = ShowPointer },
            Detail = new EChartSeriesDetail
            {
                FontSize = 24,
                Formatter = formatter
            },
            Data = new List<Dictionary<string, object>>
            {
                new() { ["value"] = Value, ["name"] = Title ?? "" }
            }
        };

        if (!string.IsNullOrEmpty(Title))
            series.Title = new EChartTitle { Text = Title };

        if (Ranges is { Count: > 0 })
        {
            // Build axis line color stops from ranges
            var colorStops = new List<object>();
            foreach (var range in Ranges.OrderBy(r => r.Threshold))
            {
                var normalizedPos = (range.Threshold - Min) / (Max - Min);
                colorStops.Add(new object[] { normalizedPos, range.Color });
            }
            // Ensure we reach 1.0
            var maxThreshold = Ranges.Max(r => r.Threshold);
            if (maxThreshold < Max)
            {
                var lastColor = Ranges.OrderBy(r => r.Threshold).Last().Color;
                colorStops.Add(new object[] { 1.0, lastColor });
            }

            series.ExtensionData = new Dictionary<string, System.Text.Json.JsonElement>
            {
                ["axisLine"] = System.Text.Json.JsonSerializer.Deserialize<System.Text.Json.JsonElement>(
                    System.Text.Json.JsonSerializer.Serialize(new
                    {
                        lineStyle = new { width = 15, color = colorStops }
                    }))
            };
        }

        if (ShowDataLabels)
            series.Label = new EChartLabel { Show = true, Position = LabelPosition, Formatter = LabelFormat };

        _option = new EChartOption
        {
            Series = new List<EChartSeries> { series },
            Color = ColorPalette
        };

        if (Toolbox)
            _option.Toolbox = new EChartToolbox { Show = true, Feature = new EChartToolboxFeature { SaveAsImage = new() { Show = true }, Restore = new() { Show = true } } };

        if (AnimationDuration.HasValue) _option.AnimationDuration = AnimationDuration;
        if (!string.IsNullOrEmpty(AnimationEasing)) _option.AnimationEasing = AnimationEasing;

        ChartHelper.ApplyOptionOverride(_option, OptionOverride);
    }

    public class GaugeRange
    {
        public double Threshold { get; set; }
        public string Color { get; set; } = "";
    }
}
