@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<GraphNode> Nodes { get; set; } = new();
    [Parameter] public List<GraphLink> Links { get; set; } = new();
    [Parameter] public List<GraphCategory> Categories { get; set; } = new();
    [Parameter] public string Layout { get; set; } = "force";
    [Parameter] public bool ShowLegend { get; set; } = true;
    [Parameter] public bool ShowTooltip { get; set; } = true;
    [Parameter] public bool Roam { 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.Graph</c> for this chart type; override if you want a different silhouette.</summary>
    [Parameter] public ChartSkeletonKind SkeletonKind { get; set; } = ChartSkeletonKind.Graph;
    /// <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; } = "right";
    [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 nodes = Nodes.Select(n => new EChartGraphNode
        {
            Name = n.Name, X = n.X, Y = n.Y,
            Value = n.Value, Category = n.Category,
            SymbolSize = n.SymbolSize ?? 20
        }).ToList();

        var links = Links.Select(l => new EChartGraphLink
        {
            Source = l.Source, Target = l.Target, Value = l.Value
        }).ToList();

        var categories = Categories.Select(c => new EChartGraphCategory { Name = c.Name }).ToList();

        var series = new EChartSeries
        {
            Type = "graph",
            Layout = Layout,
            Roam = Roam,
            Nodes = nodes,
            Links = links,
            Categories = categories,
            Label = new EChartLabel
            {
                Show = true,
                Position = ShowDataLabels ? LabelPosition : "right",
                Formatter = ShowDataLabels ? LabelFormat : null
            },
            Emphasis = new EChartEmphasis { Focus = "adjacency" }
        };

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

        if (ShowTooltip)
            _option.Tooltip = new EChartTooltip { Trigger = "item" };

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

        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 GraphNode
    {
        public string Name { get; set; } = "";
        public double? X { get; set; }
        public double? Y { get; set; }
        public double? Value { get; set; }
        public string? Category { get; set; }
        public int? SymbolSize { get; set; }
    }

    public class GraphLink
    {
        public string Source { get; set; } = "";
        public string Target { get; set; } = "";
        public double? Value { get; set; }
    }

    public class GraphCategory
    {
        public string Name { get; set; } = "";
    }
}
