@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 List<string> Categories { get; set; } = new();
    [Parameter] public List<MixedSeriesData> Series { get; set; } = new();
    [Parameter] public bool ShowLegend { get; set; } = true;
    [Parameter] public bool ShowTooltip { get; set; } = true;
    [Parameter] public List<string>? Colors { 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.Line</c> for this chart type; override if you want a different silhouette.</summary>
    [Parameter] public ChartSkeletonKind SkeletonKind { get; set; } = ChartSkeletonKind.Line;
    /// <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; }

    /// <summary>Controls category-axis label rendering. Smart auto-rotates at higher
    /// densities; ShowAll forces all horizontal; Auto thins overlapping labels.</summary>
    [Parameter] public ChartLabelStrategy LabelStrategy { get; set; } = ChartLabelStrategy.Smart;

    /// <summary>Manual rotation override (degrees) for category-axis labels.</summary>
    [Parameter] public int? LabelRotate { 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 EChartMarkLine? MarkLine { get; set; }
    [Parameter] public EChartMarkPoint? MarkPoint { get; set; }
    [Parameter] public EChartMarkArea? MarkArea { get; set; }
    [Parameter] public Dictionary<string, object>? OptionOverride { get; set; }

    private EChartOption _option = new();

    protected override void OnParametersSet()
    {
        var seriesList = Series.Select(s => new EChartSeries
        {
            Name = s.Name,
            Type = s.Type ?? "bar",
            Data = s.Values,
            Smooth = s.Type == "line" ? true : null
        }).ToList();

        if (ShowDataLabels)
            foreach (var s in seriesList)
                s.Label = new EChartLabel { Show = true, Position = LabelPosition, Formatter = LabelFormat };

        if (seriesList.Count > 0)
        {
            if (MarkLine is not null) seriesList[0].MarkLine = MarkLine;
            if (MarkPoint is not null) seriesList[0].MarkPoint = MarkPoint;
            if (MarkArea is not null) seriesList[0].MarkArea = MarkArea;
        }

        var categoryAxis = new EChartAxis { Type = "category", Data = Categories };
        ChartLabelHelper.ApplyTo(categoryAxis, LabelStrategy, Categories.Count, LabelRotate);

        _option = new EChartOption
        {
            XAxis = new List<EChartAxis> { categoryAxis },
            YAxis = new List<EChartAxis>
            {
                new() { Type = "value" }
            },
            Series = seriesList,
            Grid = new EChartGrid
            {
                Left = "3%", Right = "4%",
                Top = ShowLegend ? "14%" : "5%",
                Bottom = DataZoom ? "15%" : "3%",
                ContainLabel = true
            },
            Color = ColorPalette ?? Colors
        };

        if (ShowTooltip)
            _option.Tooltip = new EChartTooltip { Trigger = "axis", AxisPointer = new EChartAxisPointer { Type = "cross" } };

        if (ShowLegend && Series.Count > 0)
            _option.Legend = new EChartLegend { Data = Series.Select(s => s.Name).ToList() };

        if (DataZoom)
            _option.DataZoom = new List<EChartDataZoom> { new() { Type = "slider", Show = true }, new() { Type = "inside" } };

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

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

        ChartHelper.ApplyOptionOverride(_option, OptionOverride);
    }

    public class MixedSeriesData
    {
        public string Name { get; set; } = "";
        public List<double> Values { get; set; } = new();
        public string? Type { get; set; }
    }
}
