@page "/urlaub-maximizer"
@rendermode InteractiveWebAssembly
@attribute [Authorize]
@inject ITimetrackerService TrackerService
@inject IHolidayService HolidayService
@inject ISnackbar Snackbar
@inject AuthenticationStateProvider AuthStateProvider

<PageTitle>Urlaubs-Maximizer – Timetracker</PageTitle>

@if (_loading)
{
    <MudStack AlignItems="AlignItems.Center" Class="mt-16" Spacing="3">
        <MudProgressCircular Color="Color.Warning" Indeterminate="true" Size="Size.Large" />
        <MudText Color="Color.Secondary">Berechne beste Urlaubskombinationen…</MudText>
    </MudStack>
}
else
{
    <MudStack Spacing="3">

        @* ── Header ── *@
        <MudPaper Elevation="4" Class="pa-5 rounded-xl"
                  Style="background: #C2410C; color:white;">
            <MudStack Row="true" AlignItems="AlignItems.Center" Justify="Justify.SpaceBetween">
                <MudIconButton Icon="@Icons.Material.Filled.ChevronLeft"
                               Style="color:white" Size="Size.Large" OnClick="PrevYear" />
                <MudStack Spacing="0" AlignItems="AlignItems.Center">
                    <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
                        <MudIcon Icon="@Icons.Material.Filled.AutoAwesome" Style="color:white" />
                        <MudText Typo="Typo.h5" Style="color:white; font-weight:700; letter-spacing:0.5px">
                            Urlaubs-Maximizer @_year
                        </MudText>
                    </MudStack>
                    <MudText Typo="Typo.caption" Style="color:rgba(255,255,255,0.75)">
                        @_subLabel
                    </MudText>
                </MudStack>
                <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="0">
                    @if (_year != DateTime.Today.Year)
                    {
                        <MudButton Variant="Variant.Text" Style="color:white"
                                   OnClick="GoToCurrentYear" Size="Size.Small">Heute</MudButton>
                    }
                    <MudIconButton Icon="@Icons.Material.Filled.ChevronRight"
                                   Style="color:white" Size="Size.Large" OnClick="NextYear" />
                </MudStack>
            </MudStack>
        </MudPaper>

        @* ── Info-Legende ── *@
        <MudPaper Elevation="1" Class="pa-3 rounded-xl">
            <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="3" Wrap="Wrap.Wrap">
                <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
                    <div style="width:16px;height:16px;border-radius:4px;background:#3F51B5;"></div>
                    <MudText Typo="Typo.caption" Color="Color.Secondary">Urlaubstag (einzutragen)</MudText>
                </MudStack>
                <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
                    <div style="width:16px;height:16px;border-radius:4px;background:#009688;"></div>
                    <MudText Typo="Typo.caption" Color="Color.Secondary">Feiertag</MudText>
                </MudStack>
                <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
                    <div style="width:16px;height:16px;border-radius:4px;background:#FF9800;"></div>
                    <MudText Typo="Typo.caption" Color="Color.Secondary">Bereits Urlaub</MudText>
                </MudStack>
                <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="1">
                    <div style="width:16px;height:16px;border-radius:4px;background:#ECEFF1;border:1px solid #CFD8DC;"></div>
                    <MudText Typo="Typo.caption" Color="Color.Secondary">Wochenende / Frei</MudText>
                </MudStack>
                <MudDivider Vertical="true" FlexItem="true" />
                <MudText Typo="Typo.caption" Color="Color.Secondary">
                    Noch <b>@_remainingDays</b> Urlaubstage verfügbar
                </MudText>
            </MudStack>
        </MudPaper>

        @if (!_holidays.Any())
        {
            <MudAlert Severity="Severity.Info" Class="rounded-xl">
                Keine Feiertage für @_year geladen. Gehe zu
                <b>Einstellungen → Feiertage</b> und klicke „Von API laden" für optimale Vorschläge.
            </MudAlert>
        }

        @if (_remainingDays <= 0)
        {
            <MudPaper Elevation="2" Class="pa-8 rounded-xl text-center">
                <MudIcon Icon="@Icons.Material.Filled.BeachAccess"
                         Style="font-size:4rem; color:#FFB74D;" Class="mb-3" />
                <MudText Typo="Typo.h6">Alle Urlaubstage sind bereits eingetragen!</MudText>
                <MudText Typo="Typo.body2" Color="Color.Secondary" Class="mt-1">
                    Du hast dein Urlaubskontingent für @_year vollständig verplant.
                </MudText>
            </MudPaper>
        }
        else if (_suggestions.Count == 0)
        {
            <MudPaper Elevation="2" Class="pa-8 rounded-xl text-center">
                <MudIcon Icon="@Icons.Material.Filled.SearchOff"
                         Style="font-size:4rem; color:#CFD8DC;" Class="mb-3" />
                <MudText Typo="Typo.h6" Color="Color.Secondary">Keine Vorschläge gefunden</MudText>
                <MudText Typo="Typo.body2" Color="Color.Secondary" Class="mt-1">
                    Für das restliche Jahr @_year sind keine günstigen Brückentag-Kombinationen verfügbar.
                </MudText>
            </MudPaper>
        }
        else
        {
            @* ── Vorschläge gruppiert nach Urlaubstagen ── *@
            @foreach (var group in _suggestions.GroupBy(s => s.VacationDaysNeeded).OrderBy(g => g.Key))
            {
                var dayWord = group.Key == 1 ? "Urlaubstag" : "Urlaubstagen";
                var bestEff = group.Max(s => s.Efficiency);

                <MudStack Spacing="2">
                    <MudStack Row="true" AlignItems="AlignItems.Center" Spacing="2">
                        <MudText Typo="Typo.overline" Style="font-weight:700; letter-spacing:2px; color:#E65100;">
                            MIT @group.Key.ToString().ToUpper() @dayWord.ToUpper()
                        </MudText>
                        <MudChip T="string" Size="Size.Small" Variant="Variant.Outlined"
                                 Style="color:#E65100; border-color:#E65100; height:20px; font-size:11px">
                            @group.Count() Vorschlag@(group.Count() == 1 ? "" : "schläge")
                        </MudChip>
                    </MudStack>

                    <MudGrid Spacing="3">
                        @foreach (var s in group.OrderByDescending(x => x.Efficiency))
                        {
                            var effColor = s.Efficiency >= 4.0 ? "#4CAF50"
                                         : s.Efficiency >= 3.0 ? "#2196F3"
                                         : s.Efficiency >= 2.0 ? "#FF9800"
                                         : "#9E9E9E";
                            var effLabel = s.Efficiency >= 4.0 ? "Jackpot"
                                         : s.Efficiency >= 3.0 ? "Sehr gut"
                                         : s.Efficiency >= 2.0 ? "Gut"
                                         : "OK";

                            <MudItem xs="12" sm="6" lg="4">
                                <MudCard Elevation="3" Class="rounded-xl h-100"
                                         Style="@($"border-top: 4px solid {effColor};")">
                                    <MudCardContent Class="pa-4">
                                        <MudStack Spacing="3">

                                            @* Titel + Badge *@
                                            <MudStack Row="true" AlignItems="AlignItems.Start"
                                                      Justify="Justify.SpaceBetween">
                                                <MudStack Spacing="0">
                                                    <MudText Typo="Typo.h5" Style="font-weight:800; line-height:1.1">
                                                        @s.TotalFreeDays Tage frei
                                                    </MudText>
                                                    <MudText Typo="Typo.caption" Color="Color.Secondary">
                                                        für @s.VacationDaysNeeded @dayWord
                                                        · +@s.BonusDays Bonustage
                                                    </MudText>
                                                </MudStack>
                                                <MudStack Spacing="0" AlignItems="AlignItems.End">
                                                    <MudText Typo="Typo.h6"
                                                             Style="@($"font-weight:800; color:{effColor}")">
                                                        @s.Efficiency.ToString("0.0")×
                                                    </MudText>
                                                    <MudText Typo="Typo.caption"
                                                             Style="@($"color:{effColor}; font-weight:600")">
                                                        @effLabel
                                                    </MudText>
                                                </MudStack>
                                            </MudStack>

                                            @* Datum *@
                                            <MudText Typo="Typo.body2" Color="Color.Secondary">
                                                @s.SpanStart.ToString("ddd, dd. MMM", _deCulture)
                                                &nbsp;–&nbsp;
                                                @s.SpanEnd.ToString("ddd, dd. MMM yyyy", _deCulture)
                                            </MudText>

                                            @* Tages-Kacheln *@
                                            <div style="display:flex; flex-wrap:wrap; gap:4px;">
                                                @foreach (var d in DaysInSpan(s))
                                                {
                                                    var isVac     = s.VacationDaysToTake.Contains(d);
                                                    var isHol     = _holidays.ContainsKey(d);
                                                    var isTaken   = _vacationSet.Contains(d);
                                                    var bg        = isVac   ? "#3F51B5"
                                                                  : isHol   ? "#009688"
                                                                  : isTaken ? "#FF9800"
                                                                  : "#ECEFF1";
                                                    var fg        = (isVac || isHol || isTaken) ? "white" : "#607D8B";
                                                    var tooltip   = isVac   ? "Urlaubstag eintragen"
                                                                  : isHol   ? (_holidays.GetValueOrDefault(d) ?? "Feiertag")
                                                                  : isTaken ? "Bereits Urlaub"
                                                                  : "Wochenende";
                                                    <MudTooltip Text="@tooltip">
                                                        <div style="@($"display:flex;flex-direction:column;align-items:center;justify-content:center;width:36px;height:44px;border-radius:8px;background:{bg};color:{fg};")">
                                                            <span style="font-size:0.55rem;font-weight:700;letter-spacing:0.5px;line-height:1.2">
                                                                @d.ToString("ddd", _deCulture).Substring(0, 2).ToUpper()
                                                            </span>
                                                            <span style="font-size:0.85rem;font-weight:700;line-height:1.2">
                                                                @d.Day
                                                            </span>
                                                        </div>
                                                    </MudTooltip>
                                                }
                                            </div>

                                        </MudStack>
                                    </MudCardContent>
                                    <MudCardActions Class="pa-3 pt-0">
                                        <MudButton Variant="Variant.Filled"
                                                   StartIcon="@Icons.Material.Filled.BeachAccess"
                                                   Style="@($"background:{effColor}; color:white;")"
                                                   Size="Size.Small" FullWidth="true"
                                                   OnClick="@(async () => await TakeSuggestion(s))">
                                            Urlaub eintragen
                                        </MudButton>
                                    </MudCardActions>
                                </MudCard>
                            </MudItem>
                        }
                    </MudGrid>
                </MudStack>
            }
        }

    </MudStack>
}

@code {
    private static readonly System.Globalization.CultureInfo _deCulture = new("de-DE");

    private bool _loading = true;
    private int _year = DateTime.Today.Year;
    private AppSettings _settings = new();
    private Dictionary<DateOnly, string> _holidays = [];
    private HashSet<DateOnly> _vacationSet = [];
    private int _remainingDays;
    private List<Suggestion> _suggestions = [];
    private string _subLabel = "";
    private int _userId;

    protected override async Task OnInitializedAsync()
    {
        var authState = await AuthStateProvider.GetAuthenticationStateAsync();
        var claim = authState.User.FindFirst(ClaimTypes.NameIdentifier);
        if (claim == null) return;
        _userId = int.Parse(claim.Value);
        _settings = await TrackerService.GetSettingsAsync(_userId);
        await LoadYear();
        _loading = false;
    }

    private async Task LoadYear()
    {
        var holidaysTask = HolidayService.GetHolidaysAsync(_year, _settings.GermanState);
        var vacationsTask = TrackerService.GetVacationDaysAsync(_userId, _year);

        await Task.WhenAll(holidaysTask, vacationsTask);

        var holidays    = await holidaysTask;
        var vacations   = await vacationsTask;
        _holidays       = holidays.ToDictionary(h => h.Date, h => h.Name);
        _vacationSet    = vacations.Select(v => v.Date).ToHashSet();
        _remainingDays  = Math.Max(0, _settings.VacationDaysPerYear - vacations.Count);
        _suggestions    = ComputeSuggestions();
        var count       = _suggestions.Count;
        var bestEff     = count > 0 ? _suggestions.Max(s => s.Efficiency) : 0;
        _subLabel = count == 0
            ? "Keine Vorschläge verfügbar"
            : $"{count} Kombination{(count == 1 ? "" : "en")} · Beste: {bestEff:0.0}× Effizienz";
    }

    private async Task PrevYear()        { _year--; await LoadYear(); }
    private async Task NextYear()        { _year++; await LoadYear(); }
    private async Task GoToCurrentYear() { _year = DateTime.Today.Year; await LoadYear(); }

    private async Task TakeSuggestion(Suggestion s)
    {
        foreach (var d in s.VacationDaysToTake.Where(d => !_vacationSet.Contains(d)))
            await TrackerService.AddVacationDayAsync(new VacationDay { UserId = _userId, Date = d, Note = "Urlaubs-Maximizer" });
        await LoadYear();
        var word = s.VacationDaysNeeded == 1 ? "Urlaubstag" : "Urlaubstage";
        Snackbar.Add($"{s.VacationDaysNeeded} {word} eingetragen – {s.TotalFreeDays} Tage frei!", Severity.Success);
    }

    // ── Algorithmus ──────────────────────────────────────────────────────
    private enum DayKind { Free, WorkAvailable, WorkTaken }

    private sealed record Suggestion(
        DateOnly SpanStart,
        DateOnly SpanEnd,
        List<DateOnly> VacationDaysToTake,
        int VacationDaysNeeded,
        int TotalFreeDays,
        double Efficiency)
    {
        public int BonusDays => TotalFreeDays - VacationDaysNeeded;
    }

    private List<Suggestion> ComputeSuggestions()
    {
        var startOfYear = new DateOnly(_year, 1, 1);
        var endOfYear   = new DateOnly(_year, 12, 31);
        var today       = DateOnly.FromDateTime(DateTime.Today);
        int n = endOfYear.DayNumber - startOfYear.DayNumber + 1;

        // Classify each day
        var kinds = new DayKind[n];
        for (int i = 0; i < n; i++)
        {
            var d = startOfYear.AddDays(i);
            if (!_settings.IsWorkDay(d.DayOfWeek) || _holidays.ContainsKey(d))
                kinds[i] = DayKind.Free;
            else if (_vacationSet.Contains(d))
                kinds[i] = DayKind.WorkTaken;
            else
                kinds[i] = DayKind.WorkAvailable;
        }

        // Prefix sum: count of WorkAvailable days
        var psum = new int[n + 1];
        for (int i = 0; i < n; i++)
            psum[i + 1] = psum[i] + (kinds[i] == DayKind.WorkAvailable ? 1 : 0);
        int CountAvail(int a, int b) => psum[b + 1] - psum[a];

        int maxVac = Math.Min(_remainingDays, 5);
        if (maxVac <= 0) return [];

        // For each window [ws, we] of contiguous days, compute best span
        var best = new Dictionary<(int, int), Suggestion>();

        for (int ws = 0; ws < n; ws++)
        {
            if (kinds[ws] != DayKind.WorkAvailable) continue;

            for (int we = ws; we < n; we++)
            {
                int vac = CountAvail(ws, we);
                if (vac > maxVac) break;
                if (vac == 0)    continue;

                // Extend span outward through non-WorkAvailable days
                int ss = ws, se = we;
                while (ss > 0     && kinds[ss - 1] != DayKind.WorkAvailable) ss--;
                while (se < n - 1 && kinds[se + 1] != DayKind.WorkAvailable) se++;

                int total = se - ss + 1;
                if (total <= vac) continue;                    // No bonus days → skip
                if (startOfYear.AddDays(se) < today) continue; // Fully in the past → skip

                double eff = (double)total / vac;
                var key    = (ss, se);

                var vacDays = Enumerable.Range(ws, we - ws + 1)
                    .Where(i => kinds[i] == DayKind.WorkAvailable)
                    .Select(i => startOfYear.AddDays(i))
                    .ToList();

                var sug = new Suggestion(
                    startOfYear.AddDays(ss), startOfYear.AddDays(se),
                    vacDays, vac, total, eff);

                if (!best.TryGetValue(key, out var existing) || vac < existing.VacationDaysNeeded)
                    best[key] = sug;
            }
        }

        // Group by vac days needed, keep top 4 per group by efficiency
        return [.. best.Values
            .GroupBy(s => s.VacationDaysNeeded)
            .OrderBy(g => g.Key)
            .SelectMany(g => g
                .OrderByDescending(s => s.Efficiency)
                .ThenByDescending(s => s.TotalFreeDays)
                .Take(4))];
    }

    private static IEnumerable<DateOnly> DaysInSpan(Suggestion s)
    {
        for (var d = s.SpanStart; d <= s.SpanEnd; d = d.AddDays(1))
            yield return d;
    }
}
