@using Radzen
@using Radzen.Blazor
@using Radzen.Blazor.Rendering
@inject DialogService DialogService

@{
    var points = new Dictionary<AppointmentData, double>();
    var calendar = (Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture).Calendar;

    // StartDate can be shifted one extra week earlier to render a full header row.
    // Derive the base year from the scheduler's CurrentDate + StartMonth instead of StartDate.AddDays(7).Year
    // (which can incorrectly yield the previous year for StartMonth=January when the week starts on Sunday).
    var startMonthNumber = (int)StartMonth + 1; // Month enum is 0-based
    var year = Scheduler != null
        ? calendar.GetYear(Scheduler.CurrentDate.Date) + (calendar.GetMonth(Scheduler.CurrentDate.Date) < startMonthNumber ? -1 : 0)
        : calendar.GetYear(StartDate.AddDays(7));

    DateTime date = StartDate.AddDays(7);
    DateTime realstart = StartDate;
    int daysinmonth;
}


<div class="rz-view rz-year-view">
<div class="rz-display-flex rz-row rz-align-items-normal rz-justify-content-space-between">
    @for (int month = 0; month < 12; month++)
    {
        int offSetMonth = ((month + (int)StartMonth) % 12) + 1;
        int curYear = year + (offSetMonth <= month ? 1 : 0);
        realstart = new DateTime(curYear, offSetMonth, 1, calendar);
        daysinmonth = calendar.GetDaysInMonth(curYear, offSetMonth);
        date = realstart.StartOfMonth().StartOfWeek(Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture);
        var currentDate = date;
        var currentMonth = month;
        var startMonth = realstart;

        <div class="rz-year-month rz-display-flex rz-flex-column rz-col-12 rz-col-sm-6 rz-col-md-4 rz-col-lg-3"
                 tabindex="0" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeyPress" @onkeydown:stopPropagation="stopKeydownPropagation"
                 @onfocus=@(args => {CurrentDate = currentDate; CurrentMonth = currentMonth; })>

            <div class="rz-slot-header rz-pb-2" role="button" tabindex="0" @onclick=@(args => OnMonthClick(startMonth)) @onkeydown="@(args => OnMonthHeaderKeyDown(args, startMonth))">
                <span class="rz-text-subtitle1">
                    @realstart.ToString("MMMM yyyy", Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture)
                </span>
            </div>

            <div class="rz-view-header">
                @for (var dateheader = StartDate; dateheader <= StartDate.EndOfWeek(Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture); dateheader = dateheader.AddDays(1))
                {
                    <div class="rz-slot-header">
                        @dateheader.ToString("ddd", Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture).Substring(0,1)
                    </div>
                }
            </div>

            @for (var row = 0; row < 6; row++)
            {
                <div class="rz-week">
                    <div class="rz-events">
                        <div class="rz-slots">
                            @for (var col = 0; col < 7; col++)
                            {
                                var day = date.AddDays((row * 7) + col);
                                var appointments = AppointmentsInRange(day, day.AddDays(1));
                                var excessCount = appointments.Count();
                                string classname = $"rz-slot-title {(calendar.GetMonth(day) != offSetMonth ? "rz-other-month" : "")} {(excessCount > 0 ? "rz-has-appointments" : "")} {(day == CurrentDate && month == CurrentMonth ? " rz-state-focused" : "")}".Trim();

                                    <div @onclick=@(args => OnListClick(day, appointments)) @attributes=@Attributes(day, "rz-slot") role="button" tabindex="0" @onkeydown="@(args => OnDayKeyDown(args, day, appointments))">
                                        <div class="@classname">
                                            @calendar.GetDayOfMonth(day)
                                        </div>
                                    </div>
                                }
                        </div>
                    </div>
                </div>
            }
        </div>
    }
</div>
</div>

@code {
    [Parameter]
    public DateTime StartDate { get; set; }

    [Parameter]
    public DateTime EndDate { get; set; }

    [Parameter]
    public Month StartMonth { get; set; }

    [Parameter]
    public int MaxAppointmentsInSlot { get; set; }

    [Parameter]
    public string? MoreText { get; set; }

    [Parameter]
    public string? NoDayEventsText  { get; set; }

    [CascadingParameter]
    public IScheduler? Scheduler { get; set; }

    [Parameter]
    public IEnumerable<AppointmentData>? Appointments { get; set; }

    IDictionary<string, object> Attributes(DateTime start, string className)
    {
        if (Scheduler == null)
            return new Dictionary<string, object>();
        var attributes = Scheduler.GetSlotAttributes(start, start.AddDays(1), () => AppointmentsInRange(start, start.AddDays(1)));
        attributes["class"] = ClassList.Create(className).Add(attributes).ToString();
        return attributes;
    }

    async Task OnAppointmentClick(AppointmentData data)
    {
        if (Scheduler != null)
            await Scheduler.SelectAppointment(data);
    }

    private AppointmentData[] AppointmentsInRange(DateTime start, DateTime end)
    {
        if (Appointments == null || Scheduler == null)
        {
            return Array.Empty<AppointmentData>();
        }

        return Appointments.Where(item => Scheduler.IsAppointmentInRange(item, start, end)).OrderBy(item => item.Start).ThenByDescending(item => item.End).ToArray();
    }

    async Task OnMonthClick(DateTime monthStart)
    {
        if (Scheduler != null)
            await Scheduler.SelectMonth(monthStart, AppointmentsInRange(monthStart, monthStart.EndOfMonth()));
    }

    async Task OnMonthHeaderKeyDown(KeyboardEventArgs args, DateTime monthStart)
    {
        var key = args.Code != null ? args.Code : args.Key;
        if (key == "Enter" || key == "Space")
        {
            await OnMonthClick(monthStart);
        }
    }

    async Task OnListClick(DateTime date, IEnumerable<AppointmentData> appointments)
    {
        if (Scheduler == null) return;
        bool preventDefault = await Scheduler.SelectSlot(date, date.AddDays(1), appointments);

        if(!preventDefault)
        {
        if (appointments.Count() > 0)
        {
            await DialogService.OpenAsync(date.ToShortDateString(), ds =>
    @<div class="rz-event-list">
        <CascadingValue Value=@Scheduler>
            @foreach (var item in appointments)
            {
                <Appointment Data=@item Click="OnListEventClick" />
            }
        </CascadingValue>
    </div>
        );

        }
        else
        {
            await DialogService.OpenAsync(date.ToShortDateString(), ds =>
    @<div class="rz-event-list">
        @(NoDayEventsText)
    </div>
    );

        }
        }
    }

    async Task OnDayKeyDown(KeyboardEventArgs args, DateTime day, IEnumerable<AppointmentData> appointments)
    {
        var key = args.Code != null ? args.Code : args.Key;
        if (key == "Enter" || key == "Space")
        {
            await OnListClick(day, appointments);
        }
    }

    async Task OnListEventClick(AppointmentData data)
    {
        DialogService.Close();

        await OnAppointmentClick(data);
    }

    DateTime CurrentDate;
    int CurrentMonth;

    bool preventKeyPress;
    bool stopKeydownPropagation;

    async Task OnKeyPress(KeyboardEventArgs args)
    {
        var key = args.Code != null ? args.Code : args.Key;

        if (key == "ArrowLeft" || key == "ArrowRight" || key == "ArrowUp" || key == "ArrowDown")
        {
            var days = key == "ArrowLeft" || key == "ArrowRight" ? 1 : 7;
            CurrentDate = CurrentDate.AddDays(key == "ArrowLeft" || key == "ArrowUp" ? -days : days);
            preventKeyPress = true;
            stopKeydownPropagation = true;
        }
        else if (key == "Enter")
        {
            await OnListClick(CurrentDate, AppointmentsInRange(CurrentDate, CurrentDate.AddDays(1)));

            preventKeyPress = true;
            stopKeydownPropagation = true;
        }
        else
        {
            preventKeyPress = false;
            stopKeydownPropagation = false;
        }
    }
}
