@page "/components/charts/heatmap"

<PageTitle>Heatmap Chart — Lumeo</PageTitle>

<PageHeader Title="Heatmap Chart" Description="Display density or intensity across two dimensions using color gradients. Useful for activity patterns, correlation matrices, and time-based analysis." />

<Stack Gap="8">
    <ComponentDemo Title="Activity Heatmap" Description="Support ticket volume by day of week and time of day. Darker cells indicate peak load periods, helping teams plan staffing accordingly." Code="@_basicCode">
        <Container>
            <HeatmapChart XCategories="_xCats" YCategories="_yCats" Data="_data" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Sales by Region &amp; Month" Description="Monthly revenue heatmap across four regions. Custom warm color range maps low-to-high values from cream to deep red." Code="@_salesCode">
        <Container>
            <HeatmapChart XCategories="_monthCats" YCategories="_regionCats" Data="_salesData"
                          Colors="_warmSalesColors" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Server Error Rate Matrix" Description="Error rate per hour slot and weekday. Data labels always visible; DataZoom and Toolbox enabled for deeper exploration." Code="@_errorCode">
        <Container>
            <HeatmapChart XCategories="_hourCats" YCategories="_weekdayCats" Data="_errorData"
                          ShowDataLabels="true" DataZoom="true" Toolbox="true" />
        </Container>
    </ComponentDemo>

    <ComponentDemo Title="Feature Adoption Matrix" Description="Feature usage rate (%) for seven user segments across five key features. A green-to-violet scale highlights low-adoption gaps." Code="@_adoptionCode">
        <Container>
            <HeatmapChart XCategories="_featureCats" YCategories="_segmentCats" Data="_adoptionData"
                          Colors="_adoptionColors" />
        </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>
                <HeatmapChart XCategories="_xCats" YCategories="_yCats" Data="_data" 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">HeatmapChart</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">XCategories</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">[]</td>
                            <td class="p-3 text-muted-foreground">X-axis category labels.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">YCategories</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">[]</td>
                            <td class="p-3 text-muted-foreground">Y-axis category labels.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Data</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">List&lt;double[]&gt;</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">[]</td>
                            <td class="p-3 text-muted-foreground">Data points as [x, y, value] arrays.</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 range for the visual map.</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">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">Toggles the visual-map legend that explains the heatmap color scale.</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">Shows the per-cell tooltip on hover with x/y categories and value.</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">CSS width applied to the chart container.</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">CSS height applied to the chart container.</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">Overrides the ECharts theme; null follows the app's light/dark mode.</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">Renders the numeric value inside each heatmap cell.</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">"inside"</td>
                            <td class="p-3 text-muted-foreground">Position of cell data labels (e.g. inside, top, bottom).</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">ECharts format string applied to cell data 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/pan controls along the heatmap axes.</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 toolbox with save-as-image, restore, and view 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">Overrides the chart's base color palette; alternative to per-cell Colors gradient.</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">Override entry animation duration (ms); null uses the ECharts default.</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 applied to entry animations.</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">MarkLine</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EChartMarkLine?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional mark line(s) overlaid on the heatmap grid.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MarkPoint</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EChartMarkPoint?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional mark point annotations overlaid on the heatmap.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MarkArea</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">EChartMarkArea?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">Optional mark area highlight overlaid on the heatmap grid.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>
    </Stack>
</Stack>

@code {
    // Demo 1 — support ticket volume (day × time-of-day)
    private List<string> _xCats = new() { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    private List<string> _yCats = new() { "Morning", "Afternoon", "Evening" };
    private List<double[]> _data = new()
    {
        new double[] { 0, 0, 42 }, new double[] { 1, 0, 68 }, new double[] { 2, 0, 55 }, new double[] { 3, 0, 73 }, new double[] { 4, 0, 61 }, new double[] { 5, 0, 29 }, new double[] { 6, 0, 18 },
        new double[] { 0, 1, 87 }, new double[] { 1, 1, 94 }, new double[] { 2, 1, 91 }, new double[] { 3, 1, 88 }, new double[] { 4, 1, 95 }, new double[] { 5, 1, 72 }, new double[] { 6, 1, 48 },
        new double[] { 0, 2, 31 }, new double[] { 1, 2, 56 }, new double[] { 2, 2, 63 }, new double[] { 3, 2, 47 }, new double[] { 4, 2, 79 }, new double[] { 5, 2, 84 }, new double[] { 6, 2, 67 }
    };

    // Demo 2 — monthly sales by region
    private List<string> _monthCats = new() { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
    private List<string> _regionCats = new() { "North", "South", "East", "West" };
    private List<double[]> _salesData = new()
    {
        new double[] { 0,0,210 },new double[] { 1,0,185 },new double[] { 2,0,240 },new double[] { 3,0,275 },new double[] { 4,0,310 },new double[] { 5,0,290 },
        new double[] { 6,0,320 },new double[] { 7,0,340 },new double[] { 8,0,305 },new double[] { 9,0,360 },new double[] { 10,0,380 },new double[] { 11,0,420 },
        new double[] { 0,1,150 },new double[] { 1,1,165 },new double[] { 2,1,180 },new double[] { 3,1,195 },new double[] { 4,1,220 },new double[] { 5,1,240 },
        new double[] { 6,1,230 },new double[] { 7,1,250 },new double[] { 8,1,260 },new double[] { 9,1,280 },new double[] { 10,1,295 },new double[] { 11,1,330 },
        new double[] { 0,2,190 },new double[] { 1,2,175 },new double[] { 2,2,210 },new double[] { 3,2,230 },new double[] { 4,2,255 },new double[] { 5,2,270 },
        new double[] { 6,2,285 },new double[] { 7,2,300 },new double[] { 8,2,315 },new double[] { 9,2,340 },new double[] { 10,2,355 },new double[] { 11,2,390 },
        new double[] { 0,3,130 },new double[] { 1,3,142 },new double[] { 2,3,158 },new double[] { 3,3,170 },new double[] { 4,3,195 },new double[] { 5,3,210 },
        new double[] { 6,3,205 },new double[] { 7,3,225 },new double[] { 8,3,240 },new double[] { 9,3,260 },new double[] { 10,3,278 },new double[] { 11,3,310 }
    };
    private List<string> _warmSalesColors = new() { "#fef3c7", "#fcd34d", "#f97316", "#dc2626" };

    // Demo 3 — error rates (hour × weekday)
    private List<string> _hourCats = new() { "0h", "3h", "6h", "9h", "12h", "15h", "18h", "21h" };
    private List<string> _weekdayCats = new() { "Mon", "Tue", "Wed", "Thu", "Fri" };
    private List<double[]> _errorData = new()
    {
        new double[] { 0,0,0.8 },new double[] { 1,0,0.5 },new double[] { 2,0,0.3 },new double[] { 3,0,1.2 },new double[] { 4,0,2.1 },new double[] { 5,0,1.8 },new double[] { 6,0,0.9 },new double[] { 7,0,0.4 },
        new double[] { 0,1,0.6 },new double[] { 1,1,0.4 },new double[] { 2,1,0.2 },new double[] { 3,1,1.5 },new double[] { 4,1,3.2 },new double[] { 5,1,2.4 },new double[] { 6,1,1.1 },new double[] { 7,1,0.3 },
        new double[] { 0,2,0.7 },new double[] { 1,2,0.5 },new double[] { 2,2,0.4 },new double[] { 3,2,0.9 },new double[] { 4,2,1.8 },new double[] { 5,2,1.5 },new double[] { 6,2,0.8 },new double[] { 7,2,0.5 },
        new double[] { 0,3,0.5 },new double[] { 1,3,0.3 },new double[] { 2,3,0.2 },new double[] { 3,3,1.1 },new double[] { 4,3,2.5 },new double[] { 5,3,2.0 },new double[] { 6,3,1.2 },new double[] { 7,3,0.4 },
        new double[] { 0,4,1.2 },new double[] { 1,4,0.8 },new double[] { 2,4,0.6 },new double[] { 3,4,1.4 },new double[] { 4,4,1.9 },new double[] { 5,4,1.6 },new double[] { 6,4,0.7 },new double[] { 7,4,0.9 }
    };

    // Demo 4 — feature adoption (feature × segment)
    private List<string> _featureCats = new() { "Dashboard", "Reports", "API", "Alerts", "Export" };
    private List<string> _segmentCats = new() { "Free", "Starter", "Growth", "Pro", "Enterprise", "Trial", "Internal" };
    private List<double[]> _adoptionData = new()
    {
        new double[] { 0,0,95 },new double[] { 1,0,62 },new double[] { 2,0,18 },new double[] { 3,0,45 },new double[] { 4,0,30 },
        new double[] { 0,1,92 },new double[] { 1,1,78 },new double[] { 2,1,35 },new double[] { 3,1,60 },new double[] { 4,1,55 },
        new double[] { 0,2,94 },new double[] { 1,2,85 },new double[] { 2,2,68 },new double[] { 3,2,72 },new double[] { 4,2,74 },
        new double[] { 0,3,97 },new double[] { 1,3,91 },new double[] { 2,3,82 },new double[] { 3,3,88 },new double[] { 4,3,90 },
        new double[] { 0,4,99 },new double[] { 1,4,96 },new double[] { 2,4,94 },new double[] { 3,4,97 },new double[] { 4,4,98 },
        new double[] { 0,5,88 },new double[] { 1,5,55 },new double[] { 2,5,22 },new double[] { 3,5,38 },new double[] { 4,5,28 },
        new double[] { 0,6,100},new double[] { 1,6,98 },new double[] { 2,6,95 },new double[] { 3,6,99 },new double[] { 4,6,97 }
    };
    private List<string> _adoptionColors = new() { "#f0fdf4", "#86efac", "#22c55e", "#15803d", "#4c1d95" };

    private string _basicCode    = @"<HeatmapChart XCategories=""_xCats"" YCategories=""_yCats"" Data=""_data"" />";
    private string _salesCode    = @"<HeatmapChart XCategories=""_monthCats"" YCategories=""_regionCats"" Data=""_salesData"" Colors=""_warmSalesColors"" />";
    private string _errorCode    = @"<HeatmapChart XCategories=""_hourCats"" YCategories=""_weekdayCats"" Data=""_errorData"" ShowDataLabels=""true"" DataZoom=""true"" Toolbox=""true"" />";
    private string _adoptionCode = @"<HeatmapChart XCategories=""_featureCats"" YCategories=""_segmentCats"" Data=""_adoptionData"" Colors=""_adoptionColors"" />";

    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;
    }
}
