@using Radzen.Blazor
@inherits DropableViewBase

<div class="rz-view rz-day-view">
    <div class="rz-view-header" role="button" tabindex="0" @onclick=@(args => OnDayClick(@StartDate)) @onkeydown="OnHeaderKeyDown">
        <div class="rz-slot-hour-header"></div>
        <div class="rz-slot-header">
            @StartDate.ToString("ddd", Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture)
        </div>
    </div>
    <div @ref=view class="rz-view-content rz-view-content-agenda" tabindex="0" @onkeydown="@(args => OnKeyPress(args))" @onkeydown:preventDefault="@preventKeyPress" @onkeydown:stopPropagation="stopKeydownPropagation"
         @onfocus=@this.AsNonRenderingEventHandler(OnFocus)>
        @for (var date = StartDate; date < EndDate; date = date.AddDays(1))
        {
            var slotDate = date;
            var appointments = AppointmentsInSlot(date, date.AddDays(1));

            <RadzenStack Orientation="Orientation.Horizontal" Gap="0">
                <div class="rz-slot-header-agenda">
                    <RadzenStack Orientation="Orientation.Vertical" Gap="0">
                        <div class="rz-slot-header-agenda-day-number">
                            @slotDate.ToString("dd", Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture)
                        </div>
                        <div class="rz-slot-header-agenda-day-title">
                            @slotDate.ToString("ddd", Scheduler?.Culture ?? System.Globalization.CultureInfo.CurrentCulture)
                        </div>
                    </RadzenStack>
                </div>
                <div class="rz-slot-agenda">
                    <div @onclick=@(args => OnSlotClick(slotDate)) ondragover="event.preventDefault();" @ondrop=@(args => @OnDrop(slotDate)) @attributes=@Attributes(slotDate)></div>
                    <AgendaSlotEvents Appointments=@appointments MultiDayText=@MultiDayText CurrentDate="@CurrentDate" CurrentAppointment="@currentAppointment" AppointmentDragStart=@OnAppointmentDragStart />
                </div>
            </RadzenStack>
        }
    </div>
</div>

@code {
    void OnFocus()
    {
        if (CurrentDate == default(DateTime))
        {
            CurrentDate = StartDate;
        }
    }

    ElementReference view;

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

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

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

    [Parameter]
    public string MultiDayText { get; set; } = "Multi-day";

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

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

    private AppointmentData[] AppointmentsInSlot(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).ThenBy(item => item.End).ToArray();
    }

    async Task OnSlotClick(DateTime date)
    {
        if (Scheduler != null)
        {
            await Scheduler.SelectSlot(date, date, AppointmentsInSlot(date, date.AddDays(1)));
        }
    }

    async Task OnDayClick(DateTime day)
    {
        if (Scheduler != null)
        {
            await Scheduler.SelectDay(day.Date, AppointmentsInSlot(day.Date, day.Date.AddDays(1)));
        }
    }

    async Task OnHeaderKeyDown(KeyboardEventArgs args)
    {
        var key = args.Code != null ? args.Code : args.Key;
        if (key == "Enter" || key == "Space")
        {
            await OnDayClick(StartDate);
        }
    }

    IDictionary<string, object> Attributes(DateTime date)
    {
        var attributes = Scheduler?.GetSlotAttributes(date, date.AddDays(1), () => AppointmentsInSlot(date, date.AddDays(1))) ?? new Dictionary<string, object>();
        attributes["class"] = ClassList.Create("rz-slot").Add(attributes).ToString();
        attributes["dropzone"] = "move";
        return attributes;
    }

    DateTime CurrentDate;
    int currentAppointment = -1;
    bool preventKeyPress;
    bool stopKeydownPropagation;

    async Task OnKeyPress(KeyboardEventArgs args)
    {
        var key = args.Code != null ? args.Code : args.Key;
        var updown = key == "ArrowUp" || key == "ArrowDown";

        var currentAppointments = AppointmentsInSlot(CurrentDate.Date, CurrentDate.Date.AddDays(1));

        if (updown && currentAppointments.Length > 0)
        {
            currentAppointment = Math.Clamp(currentAppointment + (key == "ArrowUp" ? -1 : 1), 0, currentAppointments.Length - 1);

            preventKeyPress = true;
            stopKeydownPropagation = true;
        }
        else if (updown)
        {
            var newDate = CurrentDate.AddDays(key == "ArrowUp" ? -1 : 1);
            if (newDate >= StartDate && newDate < EndDate)
            {
                CurrentDate = newDate;
            }

            preventKeyPress = true;
            stopKeydownPropagation = true;
        }
        else if (key == "Enter")
        {
            await OnSlotClick(CurrentDate);
            await view.FocusAsync();

            preventKeyPress = true;
            stopKeydownPropagation = true;
        }
        else if (key == "Space")
        {
            if (currentAppointments.Length > 0 && currentAppointment >= 0 && currentAppointment < currentAppointments.Length && Scheduler != null)
            {
                await Scheduler.SelectAppointment(currentAppointments[currentAppointment]);
                await view.FocusAsync();
            }

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