@page "/components/charts/geo-map"
@inject HttpClient Http

<PageTitle>Geo Map Chart — Lumeo</PageTitle>

<PageHeader Title="Geo Map Chart" Description="Display data on a geographic map with color-coded regions. Supports pan, zoom, tooltips, and custom color scales." />

<Stack Gap="8">
    <ComponentDemo Title="World Population Density" Code="@_basicCode">
        <Container>
            @if (_loading)
            {
                <Flex Align="center" Justify="center" Class="rounded-lg border border-border/40 p-12 bg-muted/20">
                    <Spinner />
                    <Lumeo.Text Size="sm" Color="muted" Class="ml-3">Loading world map data...</Lumeo.Text>
                </Flex>
            }
            else if (_mapJson is not null)
            {
                <GeoMapChart MapName="world" MapJson="@_mapJson" Data="_mapData"
                             VisualMapMin="0" VisualMapMax="500" Height="450px"
                             ShowTooltip="true" Roam="true" ShowDataLabels="false" />
            }
            else
            {
                <Flex Align="center" Justify="center" Class="rounded-lg border border-border/40 p-8 bg-muted/20">
                    <Lumeo.Text Size="sm" Color="muted">Failed to load map data. Provide GeoJSON via the MapJson parameter.</Lumeo.Text>
                </Flex>
            }
        </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="@_simLoading">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>
                <GeoMapChart MapName="world" MapJson="@_mapJson" Data="_mapData" VisualMapMin="0" VisualMapMax="500" 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">GeoMapChart</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">MapName</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">"world"</td>
                            <td class="p-3 text-muted-foreground">Name to register the map under in ECharts.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">MapJson</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">GeoJSON string for the map geometry. Required.</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">object?</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">null</td>
                            <td class="p-3 text-muted-foreground">List of objects with Name and Value for each region.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">VisualMapMin</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">double</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">0</td>
                            <td class="p-3 text-muted-foreground">Minimum value for the color scale.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">VisualMapMax</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">double</td>
                            <td class="p-3 font-mono text-xs text-muted-foreground">100</td>
                            <td class="p-3 text-muted-foreground">Maximum value for the color scale.</td>
                        </tr>
                        <tr>
                            <td class="p-3 font-mono text-xs text-primary">Roam</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">Enable pan and zoom interaction on the map.</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">Blue gradient</td>
                            <td class="p-3 text-muted-foreground">Color range for the visual map (low to high).</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">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">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">Named palette used to seed region colors.</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 or hides hover tooltips on map regions.</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">Show value labels on map regions.</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 data labels relative to each region.</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 label formatter template string.</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">Enable scroll and drag zoom controls.</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">Show ECharts toolbox with save, restore, and zoom utilities.</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 length in milliseconds when rendering.</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 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 while loading.</td>
                        </tr>
                    </tbody>
                </table>
            </Stack>
        </Stack>
    </Stack>
</Stack>

@code {
    private string? _mapJson;
    private bool _loading = true;

    private List<Dictionary<string, object>> _mapData = new()
    {
        new() { ["name"] = "China", ["value"] = 450 },
        new() { ["name"] = "India", ["value"] = 420 },
        new() { ["name"] = "United States", ["value"] = 95 },
        new() { ["name"] = "Indonesia", ["value"] = 140 },
        new() { ["name"] = "Brazil", ["value"] = 75 },
        new() { ["name"] = "Russia", ["value"] = 25 },
        new() { ["name"] = "Japan", ["value"] = 340 },
        new() { ["name"] = "Germany", ["value"] = 230 },
        new() { ["name"] = "United Kingdom", ["value"] = 275 },
        new() { ["name"] = "France", ["value"] = 120 },
        new() { ["name"] = "Nigeria", ["value"] = 215 },
        new() { ["name"] = "Mexico", ["value"] = 65 },
        new() { ["name"] = "Egypt", ["value"] = 100 },
        new() { ["name"] = "Australia", ["value"] = 10 },
        new() { ["name"] = "Canada", ["value"] = 12 },
        new() { ["name"] = "South Korea", ["value"] = 500 },
        new() { ["name"] = "Italy", ["value"] = 200 },
        new() { ["name"] = "Spain", ["value"] = 95 },
        new() { ["name"] = "Turkey", ["value"] = 110 },
        new() { ["name"] = "Poland", ["value"] = 125 },
    };

    protected override async Task OnInitializedAsync()
    {
        try
        {
            _mapJson = await Http.GetStringAsync(
                "https://cdn.jsdelivr.net/npm/echarts@4.9.0/map/json/world.json");
        }
        catch
        {
            _mapJson = null;
        }
        _loading = false;
    }

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

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

    private string _basicCode = @"@inject HttpClient Http

<GeoMapChart MapName=""world"" MapJson=""@_mapJson""
             Data=""_mapData"" VisualMapMin=""0"" VisualMapMax=""500""
             Height=""450px"" Roam=""true"" />

@code {
    private string? _mapJson;
    private List<Dictionary<string, object>> _mapData = new()
    {
        new() { [""name""] = ""China"", [""value""] = 450 },
        new() { [""name""] = ""United States"", [""value""] = 95 },
        new() { [""name""] = ""Germany"", [""value""] = 230 },
        // ... more countries
    };

    protected override async Task OnInitializedAsync()
    {
        _mapJson = await Http.GetStringAsync(
            ""https://cdn.jsdelivr.net/npm/echarts@4.9.0/map/json/world.json"");
    }
}";
}
