@page "/components/charts/sankey"

<PageTitle>Sankey Chart — Lumeo</PageTitle>

<PageHeader Title="Sankey Chart" Description="Visualize flow and relationships between nodes. The width of each link is proportional to the flow quantity, making it ideal for energy flows, budget allocations, and process mapping." />

<Stack Gap="8">
    <ComponentDemo Title="Energy Flow Sankey" Description="Renewable and conventional energy sources feeding the national grid, then distributed across residential, commercial, and industrial consumers." Code="@_basicCode">
        <Container>
            <SankeyChart Nodes="_nodes" Links="_links" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Marketing Traffic Sources" Description="Website traffic from four acquisition channels flowing through landing pages and converting to demo requests or signups." Code="@_trafficCode">
        <Container>
            <SankeyChart Nodes="_trafficNodes" Links="_trafficLinks" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Budget Allocation" Description="Annual company budget flowing from total revenue through departments and into specific cost categories. Data labels identify each node." Code="@_budgetCode">
        <Container>
            <SankeyChart Nodes="_budgetNodes" Links="_budgetLinks" ShowDataLabels="true" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="User Onboarding Journey" Description="New users arriving via three entry points, progressing through activation steps and ending in retained or churned states." Code="@_journeyCode">
        <Container>
            <SankeyChart Nodes="_journeyNodes" Links="_journeyLinks" Toolbox="true" />
        </Container>
    </ComponentDemo>
    <ComponentDemo Title="Loading state" Description="Shape-aware skeleton with reserved space for legend and axes — no layout shift when real data arrives.">
        <Container>
            <Stack Gap="4">
                <Stack Direction="Stack.StackDirection.Horizontal" Gap="4" Align="center" Wrap="true">
                    <Button OnClick="SimulateLoadingAsync" Disabled="@_loading">Simulate loading</Button>
                    <Stack Direction="Stack.StackDirection.Horizontal" Gap="2" Align="center">
                        <Switch @bind-Value="_keepLoading" Id="keep-loading" />
                        <label for="keep-loading" class="text-sm text-muted-foreground cursor-pointer">Hold skeleton open</label>
                    </Stack>
                    <Stack Direction="Stack.StackDirection.Horizontal" Gap="2" Align="center">
                        <label class="text-sm text-muted-foreground">Duration: @(_simulateDurationMs / 1000.0)s</label>
                        <input type="range" min="500" max="10000" step="500" @bind-value="_simulateDurationMs" @bind-value:event="oninput" class="w-32 accent-primary" />
                    </Stack>
                    <Stack Direction="Stack.StackDirection.Horizontal" Gap="2" Align="center">
                        <label class="text-sm text-muted-foreground">Cycle: @_phantomCycleMs ms</label>
                        <input type="range" min="300" max="3000" step="100" @bind-value="_phantomCycleMs" @bind-value:event="oninput" class="w-32 accent-primary" />
                    </Stack>
                </Stack>
                <SankeyChart Nodes="_nodes" Links="_links" PhantomCycleMs="@_phantomCycleMs" IsLoading="@LoadingComputed" Height="320px" />
            </Stack>
        </Container>
    </ComponentDemo>
</Stack>

<!-- API Reference -->
<Stack Gap="6" Class="mt-12">
    <Heading Level="2">API Reference</Heading>
    <Stack Gap="8">
        <Stack>
            <Heading Level="3" Class="mb-3">SankeyChart</Heading>
            <Stack Class="rounded-lg border border-border/40 overflow-x-auto">
                <table class="w-full min-w-[600px] text-sm">
                    <thead>
                        <tr class="border-b border-border/40 bg-muted/40">
                            <th class="text-left p-3 font-medium text-foreground">Property</th>
                            <th class="text-left p-3 font-medium text-foreground">Type</th>
                            <th class="text-left p-3 font-medium text-foreground">Default</th>
                            <th class="text-left p-3 font-medium text-foreground">Description</th>
                        </tr>
                    </thead>
                    <tbody class="divide-y divide-border/40">
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Nodes</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">List&lt;SankeyNode&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">[]</td>
                            <td class="p-3 text-muted-foreground">List of nodes with a Name property.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Links</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">List&lt;SankeyLink&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">[]</td>
                            <td class="p-3 text-muted-foreground">Connections with Source, Target, and Value.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowLegend</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">true</td>
                            <td class="p-3 text-muted-foreground">Shows or hides the chart legend.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">IsLoading</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, renders a shape-matched loading skeleton in place of the chart. Bind to your async fetch state.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowLoadingSkeleton</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">true</td>
                            <td class="p-3 text-muted-foreground">Set to false to opt out of the skeleton (chart area stays empty while IsLoading is true).</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">SkeletonKind</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ChartSkeletonKind</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">(chart default)</td>
                            <td class="p-3 text-muted-foreground">Override the skeleton silhouette (Bars, Line, Area, Pie, Scatter, Grid, Generic).</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">SkeletonStyle</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">ChartSkeletonStyle</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">Phantom</td>
                            <td class="p-3 text-muted-foreground">Phantom renders the real chart with placeholder data and morphs to real data via ECharts animation. Silhouette falls back to the legacy SVG skeleton overlay.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowLoadingLabel</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">true</td>
                            <td class="p-3 text-muted-foreground">Shows a small "Loading&hellip;" pill in the top-right corner whenever <code class="rounded bg-muted px-1 py-0.5 text-xs font-mono">IsLoading</code> is true. Layered on top of any <code class="rounded bg-muted px-1 py-0.5 text-xs font-mono">SkeletonStyle</code>. Set to false for bare visuals. <strong>(rc.18)</strong></td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">LoadingText</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"Loading&hellip;"</td>
                            <td class="p-3 text-muted-foreground">Label rendered next to the spinner inside the loading pill. Set to empty to show the spinner alone. <strong>(rc.18)</strong></td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowTooltip</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">true</td>
                            <td class="p-3 text-muted-foreground">Enables the hover tooltip showing node and flow details.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Colors</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">List&lt;string&gt;?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Custom color palette for Sankey nodes and links.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Width</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"100%"</td>
                            <td class="p-3 text-muted-foreground">Chart container width as a CSS length.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Height</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"350px"</td>
                            <td class="p-3 text-muted-foreground">Chart container height as a CSS length.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Theme</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">ECharts theme name applied to this chart instance.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">PhantomCycleMs</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">int</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">1400</td>
                            <td class="p-3 text-muted-foreground">Phantom-mode refresh interval in milliseconds. Lower = faster data cycling while loading.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ShowDataLabels</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">When true, displays labels on Sankey nodes.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">LabelPosition</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">"right"</td>
                            <td class="p-3 text-muted-foreground">Position of node labels relative to each node.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">LabelFormat</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional ECharts label formatter string for node labels.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">DataZoom</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Enables zoom slider controls for dense flow diagrams.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Toolbox</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">bool</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">false</td>
                            <td class="p-3 text-muted-foreground">Shows the ECharts toolbox with export and zoom controls.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">ColorPalette</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">List&lt;string&gt;?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Alternate full color palette applied to the chart.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">AnimationDuration</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">int?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Animation duration in milliseconds when data changes.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">AnimationEasing</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">string?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">ECharts easing function name for animation curves.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>
    </Stack>
</Stack>

@code {
    // Demo 1 — energy flow
    private List<SankeyChart.SankeyNode> _nodes = new()
    {
        new() { Name = "Solar" }, new() { Name = "Wind" }, new() { Name = "Natural Gas" },
        new() { Name = "Grid" }, new() { Name = "Residential" }, new() { Name = "Commercial" }, new() { Name = "Industrial" }
    };
    private List<SankeyChart.SankeyLink> _links = new()
    {
        new() { Source = "Solar",       Target = "Grid",        Value = 45 },
        new() { Source = "Wind",        Target = "Grid",        Value = 38 },
        new() { Source = "Natural Gas", Target = "Grid",        Value = 17 },
        new() { Source = "Grid",        Target = "Residential", Value = 42 },
        new() { Source = "Grid",        Target = "Commercial",  Value = 35 },
        new() { Source = "Grid",        Target = "Industrial",  Value = 23 }
    };

    // Demo 2 — marketing traffic sources
    private List<SankeyChart.SankeyNode> _trafficNodes = new()
    {
        new() { Name = "Organic Search" }, new() { Name = "Paid Ads" },
        new() { Name = "Social" },         new() { Name = "Direct" },
        new() { Name = "Landing Page" },   new() { Name = "Pricing Page" },
        new() { Name = "Demo Request" },   new() { Name = "Signup" }
    };
    private List<SankeyChart.SankeyLink> _trafficLinks = new()
    {
        new() { Source = "Organic Search", Target = "Landing Page",  Value = 3200 },
        new() { Source = "Paid Ads",       Target = "Landing Page",  Value = 1800 },
        new() { Source = "Social",         Target = "Pricing Page",  Value = 950  },
        new() { Source = "Direct",         Target = "Pricing Page",  Value = 620  },
        new() { Source = "Landing Page",   Target = "Demo Request",  Value = 480  },
        new() { Source = "Landing Page",   Target = "Signup",        Value = 1240 },
        new() { Source = "Pricing Page",   Target = "Demo Request",  Value = 310  },
        new() { Source = "Pricing Page",   Target = "Signup",        Value = 390  }
    };

    // Demo 3 — budget allocation
    private List<SankeyChart.SankeyNode> _budgetNodes = new()
    {
        new() { Name = "Total Budget" },
        new() { Name = "Engineering" }, new() { Name = "Marketing" }, new() { Name = "Operations" },
        new() { Name = "Salaries" },    new() { Name = "Tools & Infra" }, new() { Name = "Events" },
        new() { Name = "Campaigns" },   new() { Name = "Facilities" },    new() { Name = "Support" }
    };
    private List<SankeyChart.SankeyLink> _budgetLinks = new()
    {
        new() { Source = "Total Budget", Target = "Engineering",   Value = 4200 },
        new() { Source = "Total Budget", Target = "Marketing",     Value = 1800 },
        new() { Source = "Total Budget", Target = "Operations",    Value = 1200 },
        new() { Source = "Engineering",  Target = "Salaries",      Value = 3400 },
        new() { Source = "Engineering",  Target = "Tools & Infra", Value = 800  },
        new() { Source = "Marketing",    Target = "Campaigns",     Value = 1100 },
        new() { Source = "Marketing",    Target = "Events",        Value = 700  },
        new() { Source = "Operations",   Target = "Facilities",    Value = 650  },
        new() { Source = "Operations",   Target = "Support",       Value = 550  }
    };

    // Demo 4 — user onboarding journey
    private List<SankeyChart.SankeyNode> _journeyNodes = new()
    {
        new() { Name = "App Store" },  new() { Name = "Web Signup" }, new() { Name = "Referral" },
        new() { Name = "Installed" },  new() { Name = "Onboarded" },  new() { Name = "First Value" },
        new() { Name = "Retained" },   new() { Name = "Churned" }
    };
    private List<SankeyChart.SankeyLink> _journeyLinks = new()
    {
        new() { Source = "App Store",   Target = "Installed",   Value = 1800 },
        new() { Source = "Web Signup",  Target = "Installed",   Value = 1200 },
        new() { Source = "Referral",    Target = "Installed",   Value = 600  },
        new() { Source = "Installed",   Target = "Onboarded",   Value = 2400 },
        new() { Source = "Installed",   Target = "Churned",     Value = 1200 },
        new() { Source = "Onboarded",   Target = "First Value", Value = 1760 },
        new() { Source = "Onboarded",   Target = "Churned",     Value = 640  },
        new() { Source = "First Value", Target = "Retained",    Value = 1410 },
        new() { Source = "First Value", Target = "Churned",     Value = 350  }
    };

    private string _basicCode   = @"<SankeyChart Nodes=""_nodes"" Links=""_links"" />";
    private string _trafficCode = @"<SankeyChart Nodes=""_trafficNodes"" Links=""_trafficLinks"" />";
    private string _budgetCode  = @"<SankeyChart Nodes=""_budgetNodes"" Links=""_budgetLinks"" ShowDataLabels=""true"" />";
    private string _journeyCode = @"<SankeyChart Nodes=""_journeyNodes"" Links=""_journeyLinks"" Toolbox=""true"" />";

    private bool _loading;
    private bool _keepLoading;
    private bool LoadingComputed => _loading || _keepLoading;
    private int _simulateDurationMs = 2000;
    private int _phantomCycleMs = 1400;

    private async Task SimulateLoadingAsync()
    {
        _loading = true;
        await Task.Delay(_simulateDurationMs);
        _loading = false;
    }
}
