@page "/components/calendar"

<PageTitle>Calendar — Lumeo</PageTitle>

<PageHeader Title="Calendar" Description="A date picker calendar component for selecting dates." />

<div class="mt-10 space-y-3">
    <Heading Id="when-to-use" Level="2" Class="scroll-mt-20">When to Use</Heading>
    <ul class="list-disc list-inside space-y-1 text-muted-foreground text-sm">
        <li>Displaying a visual calendar for date selection and browsing</li>
        <li>Event scheduling interfaces where users pick start and end dates</li>
        <li>Date range visualization such as booking check-in and check-out</li>
    </ul>
</div>

<Stack Gap="8" Class="mt-8">
    <ComponentDemo Title="Default" Code="@_defaultCode">
        <Flex Justify="center">
            <Stack Class="rounded-md border bg-card p-1">
                <Calendar @bind-Value="_selectedDate" />
            </Stack>
        </Flex>
        @if (_selectedDate.HasValue)
        {
            <Lumeo.Text Size="sm" Color="muted" Class="text-center mt-4">Selected: @_selectedDate.Value.ToString("MMMM d, yyyy")</Lumeo.Text>
        }
    </ComponentDemo>

    <ComponentDemo Title="Date Range Display" Code="@_rangeCode">
        <Stack Gap="4" Class="w-full max-w-sm">
            <Stack Direction="Stack.StackDirection.Horizontal" Gap="4" Class="flex-col sm:flex-row">
                <Stack Gap="1.5" Class="flex-1">
                    <Label>Check-in</Label>
                    <Stack Class="rounded-md border bg-card p-1">
                        <Calendar @bind-Value="_checkIn" />
                    </Stack>
                </Stack>
            </Stack>
            @if (_checkIn.HasValue)
            {
                <Flex Align="center" Gap="2" Class="p-3 rounded-md bg-muted/50 text-sm">
                    <DynamicIcon Name="Calendar" Class="h-4 w-4 text-muted-foreground" />
                    <Lumeo.Text As="span" Size="sm">Check-in: <strong>@_checkIn.Value.ToString("MMM d, yyyy")</strong></Lumeo.Text>
                </Flex>
            }
        </Stack>
    </ComponentDemo>

    <ComponentDemo Title="Pre-selected Date" Code="@_preselectedCode">
        <Flex Justify="center">
            <Stack Class="rounded-md border bg-card p-1">
                <Calendar @bind-Value="_preselectedDate" />
            </Stack>
        </Flex>
    </ComponentDemo>

    <ComponentDemo Title="Min & Max Date" Code="@_minMaxCode">
        <Flex Justify="center">
            <Stack Class="rounded-md border bg-card p-1">
                <Calendar @bind-Value="_constrainedDate" MinDate="@_minDate" MaxDate="@_maxDate" />
            </Stack>
        </Flex>
        <Lumeo.Text Size="sm" Color="muted" Class="text-center mt-2">Selectable range: @_minDate.ToString("MMM d") — @_maxDate.ToString("MMM d, yyyy")</Lumeo.Text>
    </ComponentDemo>

    <ComponentDemo Title="Booking calendar — disable + tooltip + badge" Code="@_bookingCode">
        <Stack Gap="2">
            <Flex Justify="center">
                <Stack Class="rounded-md border bg-card p-1">
                    <Calendar @bind-Value="_bookingDate"
                              MinDate="DateOnly.FromDateTime(DateTime.Today)"
                              MaxDate="DateOnly.FromDateTime(DateTime.Today.AddDays(60))"
                              IsDateDisabled="@IsBookedOrClosed"
                              DateClass="@GetBookingClass"
                              DateTooltip="@GetBookingTooltip"
                              DateBadge="@GetBookingBadge" />
                </Stack>
            </Flex>
            <Lumeo.Text Size="sm" Color="muted" Class="text-center">
                Hover any day for the tooltip; the badge dot indicates booking status — green = available, amber = partial, red = sold out, grey = closed.
            </Lumeo.Text>
        </Stack>
    </ComponentDemo>

    <ComponentDemo Title="Date Range" Code="@_dateRangeCode">
        <Stack Gap="2">
            <Flex Justify="center">
                <Stack Class="rounded-md border bg-card p-1">
                    <Calendar IsRange="true" @bind-RangeStart="_rangeStart" @bind-RangeEnd="_rangeEnd" />
                </Stack>
            </Flex>
            <Lumeo.Text Size="sm" Color="muted" Class="text-center">
                @if (_rangeStart.HasValue && _rangeEnd.HasValue)
                {
                    @($"Selected: {_rangeStart:MMM dd} — {_rangeEnd:MMM dd}")
                }
                else if (_rangeStart.HasValue)
                {
                    @($"Start: {_rangeStart:MMM dd} — pick end date")
                }
                else
                {
                    <Lumeo.Text As="span">Pick a start date</Lumeo.Text>
                }
            </Lumeo.Text>
        </Stack>
    </ComponentDemo>
</Stack>

<Alert Variant="Alert.AlertVariant.Info" ShowIcon="true" Class="mt-8">
    <strong>Mobile (rc.52).</strong> Swipe left or right on the day grid to navigate between months — vertical page scroll is preserved. Nav chevrons are 44&times;44 px on mobile (<code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">h-11 w-11 sm:h-7 sm:w-7</code>). Set <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">SwipeEnabled="false"</code> to opt out.
</Alert>

<div class="mt-16">
    <Heading Id="api-reference" Level="2" Class="scroll-mt-20">API Reference</Heading>

    <Heading Id="calendar" Level="3" Class="mt-8 scroll-mt-20">Calendar</Heading>
    <div class="overflow-x-auto mt-4">
        <Table>
            <TableHeader>
                <TableRow>
                    <TableHead Class="w-[180px]">Prop</TableHead>
                    <TableHead Class="w-[180px]">Type</TableHead>
                    <TableHead Class="w-[120px]">Default</TableHead>
                    <TableHead>Description</TableHead>
                </TableRow>
            </TableHeader>
            <TableBody>
                <TableRow><TableCell Class="font-mono text-xs">Value</TableCell><TableCell Class="font-mono text-xs">DateOnly?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>The currently selected date. Use with @@bind-Value for two-way binding.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">ValueChanged</TableCell><TableCell Class="font-mono text-xs">EventCallback&lt;DateOnly?&gt;</TableCell><TableCell Class="font-mono text-xs">—</TableCell><TableCell>Callback invoked when the selected date changes.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">MinDate</TableCell><TableCell Class="font-mono text-xs">DateOnly?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>The earliest selectable date. Dates before this are disabled.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">MaxDate</TableCell><TableCell Class="font-mono text-xs">DateOnly?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>The latest selectable date. Dates after this are disabled.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">IsRange</TableCell><TableCell Class="font-mono text-xs">bool</TableCell><TableCell Class="font-mono text-xs">false</TableCell><TableCell>Enables date range selection mode.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">RangeStart</TableCell><TableCell Class="font-mono text-xs">DateOnly?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>The start of the selected date range. Use with @@bind-RangeStart.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">RangeStartChanged</TableCell><TableCell Class="font-mono text-xs">EventCallback&lt;DateOnly?&gt;</TableCell><TableCell Class="font-mono text-xs">—</TableCell><TableCell>Callback invoked when the range start changes.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">RangeEnd</TableCell><TableCell Class="font-mono text-xs">DateOnly?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>The end of the selected date range. Use with @@bind-RangeEnd.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">RangeEndChanged</TableCell><TableCell Class="font-mono text-xs">EventCallback&lt;DateOnly?&gt;</TableCell><TableCell Class="font-mono text-xs">—</TableCell><TableCell>Callback invoked when the range end changes.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">NumberOfMonths</TableCell><TableCell Class="font-mono text-xs">int</TableCell><TableCell Class="font-mono text-xs">1</TableCell><TableCell>Number of months to display side by side.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">ShowWeekNumbers</TableCell><TableCell Class="font-mono text-xs">bool</TableCell><TableCell Class="font-mono text-xs">false</TableCell><TableCell>Displays ISO week numbers alongside the calendar rows.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">ShowYearPicker</TableCell><TableCell Class="font-mono text-xs">bool</TableCell><TableCell Class="font-mono text-xs">false</TableCell><TableCell>Enables the year picker view.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">InitialView</TableCell><TableCell Class="font-mono text-xs">Calendar.CalendarView</TableCell><TableCell Class="font-mono text-xs">Days</TableCell><TableCell>Initial calendar view. Values: <code>Calendar.CalendarView.Days</code>, <code>Months</code>, <code>Years</code>.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">IsDateDisabled</TableCell><TableCell Class="font-mono text-xs">Func&lt;DateTime, bool&gt;?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Custom function to disable specific dates.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">DateClass</TableCell><TableCell Class="font-mono text-xs">Func&lt;DateTime, string&gt;?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Custom function to add CSS classes to specific dates.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">DateTooltip</TableCell><TableCell Class="font-mono text-xs">Func&lt;DateTime, string?&gt;?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Per-date tooltip text rendered as the day cell's <code class="rounded bg-muted px-1.5 py-0.5 text-xs font-mono">title</code> attribute (native browser tooltip on hover). Return null/empty for no tooltip. <Badge>rc.20</Badge></TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">DateBadge</TableCell><TableCell Class="font-mono text-xs">Func&lt;DateTime, RenderFragment?&gt;?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Per-date indicator slot rendered absolutely positioned in the bottom-right of the day cell — status dots, count badges, icons. Non-interactive (pointer-events-none) so clicks still hit the day button. <Badge>rc.20</Badge></TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">SwipeEnabled</TableCell><TableCell Class="font-mono text-xs">bool</TableCell><TableCell Class="font-mono text-xs">true</TableCell><TableCell>Enables swipe-left/right on the day grid to navigate months on touch devices. Set to false to disable.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">FirstDayOfWeek</TableCell><TableCell Class="font-mono text-xs">DayOfWeek</TableCell><TableCell Class="font-mono text-xs">Sunday</TableCell><TableCell>The first day of the week in the calendar grid.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">Class</TableCell><TableCell Class="font-mono text-xs">string?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Additional CSS classes.</TableCell></TableRow>
                <TableRow><TableCell Class="font-mono text-xs">AdditionalAttributes</TableCell><TableCell Class="font-mono text-xs">Dictionary&lt;string, object&gt;?</TableCell><TableCell Class="font-mono text-xs">null</TableCell><TableCell>Additional HTML attributes.</TableCell></TableRow>
            </TableBody>
        </Table>
    </div>
</div>

<div class="mt-12">
    <Heading Id="related" Level="2" Class="scroll-mt-20">Related Components</Heading>
    <ul class="mt-4 space-y-2 text-sm">
        <li><a href="/components/date-picker" class="text-primary hover:underline">DatePicker</a> — For selecting dates via an input field with a calendar dropdown</li>
    </ul>
</div>

@code {
    private DateOnly? _selectedDate;
    private DateOnly? _preselectedDate = DateOnly.FromDateTime(DateTime.Today);
    private DateOnly? _checkIn;
    private DateOnly? _constrainedDate;
    private DateOnly _minDate = DateOnly.FromDateTime(DateTime.Today.AddDays(-7));
    private DateOnly _maxDate = DateOnly.FromDateTime(DateTime.Today.AddDays(30));
    private DateOnly? _rangeStart;
    private DateOnly? _rangeEnd;

    // Booking-style demo: synthesised hotel availability so the badges + tooltips
    // light up at varied positions across the next 60 days.
    private DateOnly? _bookingDate;
    private HashSet<DateOnly> _booked = Enumerable.Range(2, 60)
        .Where(i => i % 7 == 3 || i % 11 == 5)
        .Select(i => DateOnly.FromDateTime(DateTime.Today.AddDays(i))).ToHashSet();
    private HashSet<DateOnly> _partial = Enumerable.Range(1, 60)
        .Where(i => i % 5 == 0)
        .Select(i => DateOnly.FromDateTime(DateTime.Today.AddDays(i))).ToHashSet();
    private HashSet<DateOnly> _closed = Enumerable.Range(1, 60)
        .Select(i => DateOnly.FromDateTime(DateTime.Today.AddDays(i)))
        .Where(d => d.DayOfWeek == DayOfWeek.Sunday).ToHashSet();

    private bool IsBookedOrClosed(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        return _booked.Contains(date) || _closed.Contains(date);
    }

    private string GetBookingClass(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        if (_booked.Contains(date)) return "bg-destructive/10 text-destructive line-through";
        if (_closed.Contains(date)) return "bg-muted/40 italic";
        if (_partial.Contains(date)) return "bg-warning/15 ring-1 ring-warning/40";
        return "";
    }

    private string? GetBookingTooltip(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        if (_booked.Contains(date)) return $"{date:MMM d} — Sold out";
        if (_closed.Contains(date)) return $"{date:MMM d} — Closed (Sunday)";
        if (_partial.Contains(date)) return $"{date:MMM d} — Limited availability";
        if (date >= DateOnly.FromDateTime(DateTime.Today)) return $"{date:MMM d} — Available";
        return null;
    }

    private RenderFragment? GetBookingBadge(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        if (date < DateOnly.FromDateTime(DateTime.Today)) return null;
        var color =
            _booked.Contains(date) ? "bg-destructive" :
            _partial.Contains(date) ? "bg-warning" :
            _closed.Contains(date) ? "bg-muted-foreground/40" :
            "bg-success";
        return @<span class="@($"block h-1.5 w-1.5 rounded-full {color}")"></span>;
    }

    private string _defaultCode = @"<Calendar @bind-Value=""_selectedDate"" />";

    private string _rangeCode = @"<Stack Gap=""1.5"">
    <Label>Check-in</Label>
    <div class=""rounded-md border p-1"">
        <Calendar @bind-Value=""_checkIn"" />
    </div>
</Stack>
@if (_checkIn.HasValue)
{
    <Flex Align=""center"" Gap=""2"" Class=""p-3 rounded-md bg-muted/50 text-sm"">
        <DynamicIcon Name=""Calendar"" Class=""h-4 w-4 text-muted-foreground"" />
        <Lumeo.Text As=""span"" Size=""sm"">Check-in: <strong>@_checkIn.Value.ToString(""MMM d, yyyy"")</strong></Lumeo.Text>
    </Flex>
}";

    private string _preselectedCode = @"<Calendar @bind-Value=""_date"" />

@code {
    private DateOnly? _date = DateOnly.FromDateTime(DateTime.Today);
}";

    private string _minMaxCode = @"<Calendar @bind-Value=""_date"" MinDate=""@_minDate"" MaxDate=""@_maxDate"" />

@code {
    private DateOnly? _date;
    private DateOnly _minDate = DateOnly.FromDateTime(DateTime.Today.AddDays(-7));
    private DateOnly _maxDate = DateOnly.FromDateTime(DateTime.Today.AddDays(30));
}";

    private string _bookingCode = @"<Calendar @bind-Value=""_bookingDate""
          MinDate=""DateOnly.FromDateTime(DateTime.Today)""
          MaxDate=""DateOnly.FromDateTime(DateTime.Today.AddDays(60))""
          IsDateDisabled=""@IsBookedOrClosed""
          DateClass=""@GetBookingClass""
          DateTooltip=""@GetBookingTooltip""
          DateBadge=""@GetBookingBadge"" />

@code {
    private DateOnly? _bookingDate;
    private HashSet<DateOnly> _booked = new();      // Sold out → disabled, red strike-through
    private HashSet<DateOnly> _partial = new();     // Limited → amber ring
    private HashSet<DateOnly> _closed = new();      // Closed → disabled, grey italic

    private bool IsBookedOrClosed(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        return _booked.Contains(date) || _closed.Contains(date);
    }

    private string GetBookingClass(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        if (_booked.Contains(date))  return ""bg-destructive/10 text-destructive line-through"";
        if (_closed.Contains(date))  return ""bg-muted/40 italic"";
        if (_partial.Contains(date)) return ""bg-warning/15 ring-1 ring-warning/40"";
        return """";
    }

    private string? GetBookingTooltip(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        if (_booked.Contains(date))  return $""{date:MMM d} — Sold out"";
        if (_closed.Contains(date))  return $""{date:MMM d} — Closed"";
        if (_partial.Contains(date)) return $""{date:MMM d} — Limited availability"";
        return $""{date:MMM d} — Available"";
    }

    // Bottom-right indicator dot: green = available, amber = partial, red = booked, grey = closed.
    private RenderFragment? GetBookingBadge(DateTime d)
    {
        var date = DateOnly.FromDateTime(d);
        var color =
            _booked.Contains(date)  ? ""bg-destructive"" :
            _partial.Contains(date) ? ""bg-warning"" :
            _closed.Contains(date)  ? ""bg-muted-foreground/40"" :
            ""bg-success"";
        return @<span class=""@($""block h-1.5 w-1.5 rounded-full {color}"")""></span>;
    }
}";

    private string _dateRangeCode = @"<Calendar IsRange=""true"" @bind-RangeStart=""_rangeStart"" @bind-RangeEnd=""_rangeEnd"" />

@if (_rangeStart.HasValue && _rangeEnd.HasValue)
{
    <Lumeo.Text Size=""sm"" Color=""muted"">Selected: @($""{_rangeStart:MMM dd} — {_rangeEnd:MMM dd}"")</Lumeo.Text>
}

@code {
    private DateOnly? _rangeStart;
    private DateOnly? _rangeEnd;
}";
}
