<?php $events = isset($events) && is_array($events) ? $events : array(); ?>

<style type="text/css">
    .cal-day-cell {
        position: relative;
        display: flex;        
        flex-direction: column;
        justify-content: flex-start;
        overflow: hidden;
        background: hsl(var(--card));
    }

    .cal-day-cell::after {
        content: "";
        position: absolute;
        inset: 0;
        pointer-events: none;
        border: 1px solid transparent;
        transition: border-color 0.2s ease;
    }

    .cal-day-cell:hover::after {
        border-color: hsl(var(--primary) / 0.25);
    }

    .cal-empty-cell {
        height: 140px;
        background:
            repeating-linear-gradient(-45deg,
                hsl(var(--muted) / 0.12),
                hsl(var(--muted) / 0.12) 4px,
                transparent 4px,
                transparent 10px),
            hsl(var(--background));
    }

    .cal-month-pill {
        border-radius: 0.9rem;
        padding: 0.25rem 0.55rem;
        color: #fff;
        font-size: 0.75rem;
        font-weight: 600;
        line-height: 1;
        box-shadow: 0 10px 22px -18px rgba(15, 23, 42, 0.45);
    }
</style>

<div class="overflow-hidden rounded-2xl border border-border bg-card shadow-sm">
    <div data-cal-weekdays class="grid grid-cols-7 border-b border-border bg-muted/20 text-sm font-semibold text-muted-foreground">
        <div class="px-3 py-4 text-center">Sunday</div>
        <div class="px-3 py-4 text-center">Monday</div>
        <div class="px-3 py-4 text-center">Tuesday</div>
        <div class="px-3 py-4 text-center">Wednesday</div>
        <div class="px-3 py-4 text-center">Thursday</div>
        <div class="px-3 py-4 text-center">Friday</div>
        <div class="px-3 py-4 text-center">Saturday</div>
    </div>
    <div id="calendar_grid" class="grid min-h-[760px] grid-cols-7 gap-px bg-border"></div>
</div>

<script id="calendar_events" type="application/json"><?= json_encode($events, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?></script>
<script>
(() => {
    const initCalendar = () => {
    const parseDate = (value) => {
        if (!value) return null;
        if (value instanceof Date) return value;
        const s = String(value).trim();
        if (/^\d{4}-\d{2}-\d{2}/.test(s)) {
            const d = new Date(`${s.slice(0, 10)}T00:00:00`);
            return isNaN(d) ? null : d;
        }
        if (/^\d{2}\.\d{2}\.\d{4}$/.test(s)) {
            const [m, d, y] = s.split(".");
            const dt = new Date(`${y}-${m}-${d}T00:00:00`);
            return isNaN(dt) ? null : dt;
        }
        const dt = new Date(s);
        return isNaN(dt) ? null : dt;
    };

    const normalizeEvents = (items) => (items || []).map((e) => {
        const startDate = parseDate(e.start);
        const endDate = parseDate(e.end) || startDate;
        if (startDate && endDate && endDate < startDate) {
            return { ...e, startDate, endDate: startDate };
        }
        return { ...e, startDate, endDate };
    }).filter((e) => e.startDate);
    let events = normalizeEvents(JSON.parse(document.getElementById("calendar_events").textContent || "[]"));

    const state = {
        view: "month",
        current: new Date(),
        selected: new Date(),
    };

    const grid = document.getElementById("calendar_grid");
    const titleEl = document.querySelector("[data-cal-title]");
    const weekdayHeader = document.querySelector("[data-cal-weekdays]");
    const modal = document.getElementById("calendar_event_modal");
    const modalTitle = document.getElementById("calendar_event_title");
    const modalSubtitle = document.getElementById("calendar_event_subtitle");
    const modalList = document.getElementById("calendar_event_list");
    const modalEmpty = document.getElementById("calendar_event_empty");
    const modalCreate = document.querySelector("[data-cal-modal-create]");
    const createModal = document.getElementById("calendar_create_modal");
    const createSubtitle = document.getElementById("calendar_create_subtitle");
    const createStart = document.getElementById("calendar_create_start");
    const createEnd = document.getElementById("calendar_create_end");
    const filterSelect = document.getElementById("calendar_filter");
    const dayClickDelay = 220;
    let lastModalDate = null;
    let dayClickTimer = null;
    let isLoadingFilter = false;

    const fmtMonth = new Intl.DateTimeFormat(undefined, { month: "long", year: "numeric" });
    const fmtDay = new Intl.DateTimeFormat(undefined, { weekday: "long", month: "long", day: "numeric", year: "numeric" });
    const fmtShort = new Intl.DateTimeFormat(undefined, { month: "short", day: "numeric" });
    const escapeHtml = (value) => String(value ?? "")
        .replace(/&/g, "&amp;")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#39;");

    const formatInputDate = (date) => {
        const d = new Date(date.getFullYear(), date.getMonth(), date.getDate());
        const month = String(d.getMonth() + 1).padStart(2, "0");
        const day = String(d.getDate()).padStart(2, "0");
        return `${d.getFullYear()}-${month}-${day}`;
    };

    const sameDay = (a, b) =>
        a.getFullYear() === b.getFullYear() &&
        a.getMonth() === b.getMonth() &&
        a.getDate() === b.getDate();

    const dayKey = (date) => date.getFullYear() * 10000 + (date.getMonth() + 1) * 100 + date.getDate();
    const inRange = (date, start, end) => {
        if (!start) return false;
        const d = dayKey(date);
        const s = dayKey(start);
        const e = dayKey(end || start);
        return d >= s && d <= e;
    };

    const eventsForDate = (date) => events.filter((e) => inRange(date, e.startDate, e.endDate));

    const qsa = (sel, root = document) => Array.from(root.querySelectorAll(sel));
    const setGridColumns = (count) => {
        if (grid) {
            grid.style.gridTemplateColumns = `repeat(${count}, minmax(0, 1fr))`;
        }
        if (weekdayHeader) {
            weekdayHeader.style.gridTemplateColumns = `repeat(${count}, minmax(0, 1fr))`;
        }
    };

    if (!grid || !titleEl || !weekdayHeader) {
        return;
    }

    const renderEventCard = (event) => {
        const color = event.color || "#6366f1";
        const title = escapeHtml(event.title);
        return `
            <a href="${event.url || "#"}" class="flex items-start gap-3 rounded-lg border border-border bg-card p-3 text-foreground transition-colors hover:bg-muted/30">
                <span class="mt-1 h-2.5 w-2.5 rounded-full" style="background:${color}"></span>
                <div class="min-w-0">
                    <div class="text-sm font-semibold truncate">${title}</div>
                    <div class="text-xs text-muted-foreground">${fmtShort.format(event.startDate)}</div>
                </div>
            </a>`;
    };

    const renderModal = (date) => {
        if (!modal) return;
        const dayEvents = eventsForDate(date);
        modalTitle.textContent = `<?= lang('events') ?> (${dayEvents.length})`;
        modalSubtitle.textContent = fmtDay.format(date);
        modalList.innerHTML = dayEvents.map(renderEventCard).join("");
        modalEmpty.classList.toggle("hidden", dayEvents.length > 0);
        modal.classList.remove("hidden");
        modal.classList.add("flex");
        lastModalDate = date;
    };

    const renderCreateModal = (date) => {
        if (!createModal) return;
        const formatted = formatInputDate(date);
        if (createStart) createStart.value = formatted;
        if (createEnd) createEnd.value = formatted;
        if (createSubtitle) createSubtitle.textContent = fmtDay.format(date);
        createModal.classList.remove("hidden");
        createModal.classList.add("flex");
    };

    const closeModal = (element) => {
        element?.classList.add("hidden");
        element?.classList.remove("flex");
    };

    const renderMonth = () => {
        grid.innerHTML = "";
        const year = state.current.getFullYear();
        const month = state.current.getMonth();
        const first = new Date(year, month, 1);
        const firstWeekday = first.getDay();
        const daysInMonth = new Date(year, month + 1, 0).getDate();
        const totalCells = Math.ceil((firstWeekday + daysInMonth) / 7) * 7;

        if (titleEl) {
            titleEl.textContent = fmtMonth.format(state.current);
        }

        weekdayHeader?.classList.remove("hidden");
        setGridColumns(7);

        for (let i = 0; i < firstWeekday; i += 1) {
            grid.insertAdjacentHTML(
                "beforeend",
                `<div class="cal-empty-cell"></div>`
            );
        }

        for (let day = 1; day <= daysInMonth; day += 1) {
            const cursor = new Date(year, month, day);
            const dayEvents = eventsForDate(cursor);
            const isSelected = sameDay(cursor, state.selected);
            const isToday = sameDay(cursor, new Date());
            grid.insertAdjacentHTML(
                "beforeend",
                `<button type="button" data-date="${cursor.toISOString()}"
                    class="cal-day-cell group px-3 py-3 text-left text-xs transition-colors focus-visible:outline-none ${isSelected ? "ring-2 ring-primary/55 ring-inset" : ""}">
                    <div class="space-y-2">
                        ${dayEvents.slice(0, 3).map((e) => `<div class="cal-month-pill truncate" style="background:${e.color || "#6366f1"}">${escapeHtml(e.title)}</div>`).join("")}
                    </div>
                    <div class="mt-auto flex items-end justify-between gap-2 pt-4">
                        ${dayEvents.length > 3 ? `<span class="inline-flex items-center rounded-full border border-border bg-background px-2.5 py-1 text-[11px] font-medium text-muted-foreground">+${dayEvents.length - 3} more</span>` : "<span></span>"}
                        <span class="font-semibold leading-none ${isToday ? "text-primary" : "text-foreground/70"}">${day}</span>
                    </div>
                </button>`
            );
        }

        for (let i = firstWeekday + daysInMonth; i < totalCells; i += 1) {
            grid.insertAdjacentHTML(
                "beforeend",
                `<div class="cal-empty-cell"></div>`
            );
        }
    };

    const renderWeek = () => {
        grid.innerHTML = "";
        const start = new Date(state.current);
        start.setDate(start.getDate() - start.getDay());
        const end = new Date(start);
        end.setDate(start.getDate() + 6);

        if (titleEl) {
            titleEl.textContent = `${fmtDay.format(start)} - ${fmtDay.format(end)}`;
        }
        weekdayHeader?.classList.remove("hidden");
        setGridColumns(7);

        let cursor = new Date(start);
        for (let i = 0; i < 7; i += 1) {
            const dayEvents = eventsForDate(cursor);
            const isSelected = sameDay(cursor, state.selected);
            const isToday = sameDay(cursor, new Date());
            grid.insertAdjacentHTML(
                "beforeend",
                `<button type="button" data-date="${cursor.toISOString()}"
                    class="cal-day-cell group min-h-[180px] dark:bg-card bg-white px-3 py-3 text-left text-xs transition-colors focus-visible:outline-none md:min-h-[220px] ${isSelected ? "ring-2 ring-primary/55 ring-inset" : ""}">
                    <div class="flex items-center justify-between">
                        <span class="text-sm font-semibold ${isToday ? "text-primary" : "text-foreground"}">${fmtShort.format(cursor)}</span>
                        ${dayEvents.length ? `<span class="text-[10px] text-muted-foreground">${dayEvents.length}</span>` : ""}
                    </div>
                    <div class="mt-3 space-y-1.5">
                        ${dayEvents.slice(0, 4).map((e) => `
                            <div class="flex items-start gap-2 rounded-md border border-border bg-card/90 px-2 py-1 text-[11px] text-foreground">
                                <span class="mt-1 h-2 w-2 rounded-full" style="background:${e.color || "#6366f1"}"></span>
                                <span class="truncate">${escapeHtml(e.title)}</span>
                            </div>`).join("")}
                        ${dayEvents.length > 4 ? `<div class="text-[10px] text-muted-foreground">+${dayEvents.length - 4} more</div>` : ""}
                    </div>
                </button>`
            );
            cursor.setDate(cursor.getDate() + 1);
        }
    };

    const renderDay = () => {
        grid.innerHTML = "";
        const dayEvents = eventsForDate(state.current);
        if (titleEl) {
            titleEl.textContent = fmtDay.format(state.current);
        }
        weekdayHeader?.classList.add("hidden");
        setGridColumns(1);

        grid.insertAdjacentHTML(
            "beforeend",
            `<div class="bg-background px-5 py-5 text-sm">
                <div class="flex items-center justify-between">
                    <div class="text-base font-semibold text-foreground">${fmtDay.format(state.current)}</div>
                    <button type="button" data-date="${state.current.toISOString()}" class="text-xs font-semibold text-primary hover:text-primary/80"><?= lang('view') ?></button>
                </div>
                <div class="mt-4 space-y-3">
                    ${dayEvents.map(renderEventCard).join("")}
                </div>
            </div>`
        );
    };

    const render = () => {
        qsa("[data-cal-view]").forEach((btn) => {
            btn.classList.toggle("cal-view-active", btn.dataset.calView === state.view);
        });
        if (state.view === "week") {
            renderWeek();
        } else if (state.view === "day") {
            renderDay();
        } else {
            renderMonth();
        }
    };

    const selectDate = (value) => {
        const date = new Date(value);
        state.selected = date;
        state.current = new Date(date);
        render();
        return date;
    };

    const setFilterLoadingState = (loading) => {
        isLoadingFilter = loading;
        if (!filterSelect) {
            return;
        }
        filterSelect.disabled = loading;
        filterSelect.classList.toggle("opacity-70", loading);
        filterSelect.classList.toggle("cursor-wait", loading);
    };

    const updateHistoryUrl = (searchType) => {
        if (!filterSelect?.dataset.historyUrl || !window.history?.replaceState) {
            return;
        }
        window.history.replaceState({}, "", `${filterSelect.dataset.historyUrl}${searchType}`);
    };

    const loadEventsForFilter = async (searchType) => {
        if (!filterSelect?.dataset.eventsUrl || isLoadingFilter) {
            return;
        }
        setFilterLoadingState(true);
        try {
            const response = await fetch(`${filterSelect.dataset.eventsUrl}${encodeURIComponent(searchType)}`, {
                headers: {
                    "X-Requested-With": "XMLHttpRequest",
                    "Accept": "application/json"
                },
                credentials: "same-origin"
            });
            if (!response.ok) {
                throw new Error(`Calendar filter request failed with status ${response.status}`);
            }
            const payload = await response.json();
            events = normalizeEvents(payload.events || []);
            closeModal(modal);
            closeModal(createModal);
            render();
            updateHistoryUrl(payload.searchType || searchType);
        } catch (error) {
            console.error(error);
        } finally {
            setFilterLoadingState(false);
        }
    };

    document.addEventListener("click", (e) => {
        const btn = e.target.closest("[data-date]");
        if (btn) {
            if (dayClickTimer) {
                clearTimeout(dayClickTimer);
            }
            dayClickTimer = window.setTimeout(() => {
                const selectedDate = selectDate(btn.dataset.date);
                renderModal(selectedDate);
                dayClickTimer = null;
            }, dayClickDelay);
            return;
        }
        const viewBtn = e.target.closest("[data-cal-view]");
        if (viewBtn) {
            state.view = viewBtn.dataset.calView;
            state.current = new Date(state.selected);
            render();
        }
        const createBtn = e.target.closest("[data-cal-create]");
        if (createBtn) {
            renderCreateModal(state.selected || new Date());
        }
    });

    filterSelect?.addEventListener("change", (e) => {
        const nextFilter = e.target.value || "all";
        loadEventsForFilter(nextFilter);
    });

    document.querySelector("[data-cal-prev]")?.addEventListener("click", () => {
        if (state.view === "week") {
            state.current.setDate(state.current.getDate() - 7);
        } else if (state.view === "day") {
            state.current.setDate(state.current.getDate() - 1);
        } else {
            state.current.setMonth(state.current.getMonth() - 1);
        }
        state.selected = new Date(state.current);
        render();
    });
    document.querySelector("[data-cal-next]")?.addEventListener("click", () => {
        if (state.view === "week") {
            state.current.setDate(state.current.getDate() + 7);
        } else if (state.view === "day") {
            state.current.setDate(state.current.getDate() + 1);
        } else {
            state.current.setMonth(state.current.getMonth() + 1);
        }
        state.selected = new Date(state.current);
        render();
    });
    document.querySelector("[data-cal-today]")?.addEventListener("click", () => {
        state.current = new Date();
        state.selected = new Date();
        render();
    });

    document.addEventListener("dblclick", (e) => {
        const btn = e.target.closest("[data-date]");
        if (!btn) {
            return;
        }
        if (dayClickTimer) {
            clearTimeout(dayClickTimer);
            dayClickTimer = null;
        }
        const selectedDate = selectDate(btn.dataset.date);
        if (createModal) {
            renderCreateModal(selectedDate);
            return;
        }
        renderModal(selectedDate);
    });

    qsa("[data-cal-modal-close]").forEach((btn) => {
        btn.addEventListener("click", () => {
            closeModal(modal);
        });
    });
    if (modalCreate) {
        modalCreate.addEventListener("click", () => {
            if (!lastModalDate) return;
            closeModal(modal);
            renderCreateModal(lastModalDate);
        });
    }
    qsa("[data-cal-create-close]").forEach((btn) => {
        btn.addEventListener("click", () => {
            closeModal(createModal);
        });
    });
    modal?.addEventListener("click", (e) => {
        if (e.target === modal) {
            closeModal(modal);
        }
    });
    createModal?.addEventListener("click", (e) => {
        if (e.target === createModal) {
            closeModal(createModal);
        }
    });

    render();
    };

    if (document.readyState === "loading") {
        document.addEventListener("DOMContentLoaded", initCalendar, { once: true });
        return;
    }

    initCalendar();
})();
</script>
