/**
 * Themis Date Picker — DaisyUI calendar widget.
 *
 * Activates on inputs with class:
 *   - "themis-date-picker"      → date only
 *   - "themis-datetime-picker"  → date + time (time handled by time-picker.js)
 *   - "themis-monthday-picker"  → month-day only (no year)
 *
 * Reads user preferences from body data attributes:
 *   data-user-date-format  — "YYYY-MM-DD", "DD/MM/YYYY", "MM/DD/YYYY",
 *                            "DD.MM.YYYY", "DD-MM-YYYY"
 *   data-user-week-start   — "monday", "sunday", or "saturday"
 *
 * Internal value always uses ISO format (YYYY-MM-DD) for Django compatibility.
 * Display value uses the user's preferred format.
 */
(function () {
    "use strict";

    // ── Preferences ──────────────────────────────────────────────────
    var body = document.body;
    var dateFormat = body.getAttribute("data-user-date-format") || "YYYY-MM-DD";
    var weekStart = body.getAttribute("data-user-week-start") || "monday";

    var WEEK_START_MAP = { sunday: 0, monday: 1, saturday: 6 };
    var weekStartDay = WEEK_START_MAP[weekStart] !== undefined ? WEEK_START_MAP[weekStart] : 1;

    var MONTH_NAMES = [
        "January", "February", "March", "April", "May", "June",
        "July", "August", "September", "October", "November", "December"
    ];
    var DAY_NAMES_SHORT = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];

    // ── Format helpers ───────────────────────────────────────────────

    function zeroPad(n) {
        return n < 10 ? "0" + n : "" + n;
    }

    /** Format a Date to the user's preferred display string. */
    function formatDate(date) {
        var y = date.getFullYear();
        var m = zeroPad(date.getMonth() + 1);
        var d = zeroPad(date.getDate());
        switch (dateFormat) {
            case "DD/MM/YYYY": return d + "/" + m + "/" + y;
            case "MM/DD/YYYY": return m + "/" + d + "/" + y;
            case "DD.MM.YYYY": return d + "." + m + "." + y;
            case "DD-MM-YYYY": return d + "-" + m + "-" + y;
            default:           return y + "-" + m + "-" + d;
        }
    }

    /** Format a Date to ISO YYYY-MM-DD (for hidden/actual value). */
    function toISO(date) {
        return date.getFullYear() + "-" + zeroPad(date.getMonth() + 1) + "-" + zeroPad(date.getDate());
    }

    /** Format month-day MM-DD. */
    function formatMonthDay(date) {
        return zeroPad(date.getMonth() + 1) + "-" + zeroPad(date.getDate());
    }

    /** Parse user-formatted string back to a Date (or null). */
    function parseDisplayDate(str) {
        if (!str) return null;
        var parts, y, m, d;
        switch (dateFormat) {
            case "DD/MM/YYYY":
                parts = str.split("/");
                if (parts.length === 3) { d = +parts[0]; m = +parts[1]; y = +parts[2]; }
                break;
            case "MM/DD/YYYY":
                parts = str.split("/");
                if (parts.length === 3) { m = +parts[0]; d = +parts[1]; y = +parts[2]; }
                break;
            case "DD.MM.YYYY":
                parts = str.split(".");
                if (parts.length === 3) { d = +parts[0]; m = +parts[1]; y = +parts[2]; }
                break;
            case "DD-MM-YYYY":
                parts = str.split("-");
                if (parts.length === 3) { d = +parts[0]; m = +parts[1]; y = +parts[2]; }
                break;
            default: // YYYY-MM-DD
                parts = str.split("-");
                if (parts.length === 3) { y = +parts[0]; m = +parts[1]; d = +parts[2]; }
                break;
        }
        if (y && m && d && m >= 1 && m <= 12 && d >= 1 && d <= 31) {
            return new Date(y, m - 1, d);
        }
        return null;
    }

    /** Parse MM-DD string to a Date in a reference year. */
    function parseMonthDay(str) {
        if (!str) return null;
        var parts = str.split("-");
        if (parts.length === 2) {
            var m = +parts[0], d = +parts[1];
            if (m >= 1 && m <= 12 && d >= 1 && d <= 31) {
                return new Date(2000, m - 1, d);
            }
        }
        return null;
    }

    // ── Day header labels rotated to week start ──────────────────────

    function getDayHeaders() {
        var headers = [];
        for (var i = 0; i < 7; i++) {
            headers.push(DAY_NAMES_SHORT[(weekStartDay + i) % 7]);
        }
        return headers;
    }

    // ── Calendar data ────────────────────────────────────────────────

    function getCalendarDays(year, month) {
        var firstOfMonth = new Date(year, month, 1);
        var lastOfMonth = new Date(year, month + 1, 0);
        var startDow = firstOfMonth.getDay();
        // Offset from week start
        var offset = (startDow - weekStartDay + 7) % 7;
        var days = [];

        // Previous month fill
        for (var i = offset - 1; i >= 0; i--) {
            var d = new Date(year, month, -i);
            days.push({ date: d, otherMonth: true });
        }
        // Current month
        for (var j = 1; j <= lastOfMonth.getDate(); j++) {
            days.push({ date: new Date(year, month, j), otherMonth: false });
        }
        // Next month fill (complete last row)
        while (days.length % 7 !== 0) {
            var next = new Date(year, month + 1, days.length - offset - lastOfMonth.getDate() + 1);
            days.push({ date: next, otherMonth: true });
        }
        return days;
    }

    function isSameDay(a, b) {
        return a && b &&
            a.getFullYear() === b.getFullYear() &&
            a.getMonth() === b.getMonth() &&
            a.getDate() === b.getDate();
    }

    // ── Year selector range ──────────────────────────────────────────

    function getYearRange() {
        var current = new Date().getFullYear();
        var years = [];
        for (var y = current - 100; y <= current + 20; y++) {
            years.push(y);
        }
        return years;
    }

    // ── Popup builder ────────────────────────────────────────────────

    function createPopup(input, isMonthDay) {
        var popup = document.createElement("div");
        popup.className = "themis-picker-popup card bg-base-200 shadow-xl";
        popup.style.position = "absolute";
        popup.style.zIndex = "9999";

        var today = new Date();
        var selectedDate = null;
        var viewYear, viewMonth;

        // Parse existing value
        if (isMonthDay) {
            selectedDate = parseMonthDay(input.value);
            viewYear = 2000;
            viewMonth = selectedDate ? selectedDate.getMonth() : today.getMonth();
        } else {
            // Try parsing as display format first, then ISO
            selectedDate = parseDisplayDate(input.value);
            if (!selectedDate && input.value) {
                var isoParts = input.value.split("-");
                if (isoParts.length === 3) {
                    selectedDate = new Date(+isoParts[0], +isoParts[1] - 1, +isoParts[2]);
                }
            }
            viewYear = selectedDate ? selectedDate.getFullYear() : today.getFullYear();
            viewMonth = selectedDate ? selectedDate.getMonth() : today.getMonth();
        }

        function render() {
            popup.innerHTML = "";

            // ── Header: nav + month/year ──
            var header = document.createElement("div");
            header.className = "flex items-center justify-between mb-2 gap-1";

            var prevBtn = document.createElement("button");
            prevBtn.type = "button";
            prevBtn.className = "btn btn-ghost btn-sm btn-square";
            prevBtn.innerHTML = "&#9664;";
            prevBtn.title = "Previous month";
            prevBtn.addEventListener("click", function (e) {
                e.preventDefault();
                e.stopPropagation();
                viewMonth--;
                if (viewMonth < 0) { viewMonth = 11; viewYear--; }
                render();
            });

            var nextBtn = document.createElement("button");
            nextBtn.type = "button";
            nextBtn.className = "btn btn-ghost btn-sm btn-square";
            nextBtn.innerHTML = "&#9654;";
            nextBtn.title = "Next month";
            nextBtn.addEventListener("click", function (e) {
                e.preventDefault();
                e.stopPropagation();
                viewMonth++;
                if (viewMonth > 11) { viewMonth = 0; viewYear++; }
                render();
            });

            var titleArea = document.createElement("div");
            titleArea.className = "flex items-center gap-1";

            // Month select
            var monthSelect = document.createElement("select");
            monthSelect.className = "select select-ghost select-sm font-semibold";
            for (var mi = 0; mi < 12; mi++) {
                var opt = document.createElement("option");
                opt.value = mi;
                opt.textContent = MONTH_NAMES[mi];
                if (mi === viewMonth) opt.selected = true;
                monthSelect.appendChild(opt);
            }
            monthSelect.addEventListener("change", function (e) {
                e.stopPropagation();
                viewMonth = +this.value;
                render();
            });
            titleArea.appendChild(monthSelect);

            // Year select (unless month-day mode)
            if (!isMonthDay) {
                var yearSelect = document.createElement("select");
                yearSelect.className = "select select-ghost select-sm font-semibold";
                var years = getYearRange();
                for (var yi = 0; yi < years.length; yi++) {
                    var yOpt = document.createElement("option");
                    yOpt.value = years[yi];
                    yOpt.textContent = years[yi];
                    if (years[yi] === viewYear) yOpt.selected = true;
                    yearSelect.appendChild(yOpt);
                }
                yearSelect.addEventListener("change", function (e) {
                    e.stopPropagation();
                    viewYear = +this.value;
                    render();
                });
                titleArea.appendChild(yearSelect);
            }

            header.appendChild(prevBtn);
            header.appendChild(titleArea);
            header.appendChild(nextBtn);
            popup.appendChild(header);

            // ── Day-of-week headers ──
            var grid = document.createElement("div");
            grid.className = "themis-calendar-grid";

            var dayHeaders = getDayHeaders();
            for (var h = 0; h < dayHeaders.length; h++) {
                var hCell = document.createElement("div");
                hCell.className = "day-header text-xs font-semibold opacity-60 py-1";
                hCell.textContent = dayHeaders[h];
                grid.appendChild(hCell);
            }

            // ── Day cells ──
            var days = getCalendarDays(viewYear, viewMonth);
            for (var di = 0; di < days.length; di++) {
                (function (dayInfo) {
                    var cell = document.createElement("button");
                    cell.type = "button";
                    cell.className = "btn btn-ghost btn-sm btn-square text-sm";

                    if (dayInfo.otherMonth) {
                        cell.classList.add("opacity-30");
                    }
                    if (isSameDay(dayInfo.date, today) && !isMonthDay) {
                        cell.classList.remove("btn-ghost");
                        cell.classList.add("btn-outline");
                    }
                    if (isSameDay(dayInfo.date, selectedDate)) {
                        cell.classList.remove("btn-ghost", "btn-outline");
                        cell.classList.add("btn-primary");
                    }
                    cell.textContent = dayInfo.date.getDate();

                    cell.addEventListener("click", function (e) {
                        e.preventDefault();
                        e.stopPropagation();
                        selectedDate = dayInfo.date;

                        if (isMonthDay) {
                            input.value = formatMonthDay(dayInfo.date);
                        } else {
                            // For datetime inputs, preserve time portion
                            if (input.classList.contains("themis-datetime-picker")) {
                                var timePart = "";
                                if (input.value) {
                                    var spaceIdx = input.value.indexOf(" ");
                                    if (spaceIdx > -1) {
                                        timePart = input.value.substring(spaceIdx);
                                    }
                                }
                                input.value = formatDate(dayInfo.date) + timePart;
                            } else {
                                input.value = formatDate(dayInfo.date);
                            }
                        }

                        // Fire change event
                        input.dispatchEvent(new Event("change", { bubbles: true }));
                        closePopup();
                    });

                    grid.appendChild(cell);
                })(days[di]);
            }

            popup.appendChild(grid);

            // ── Today button (not for month-day) ──
            if (!isMonthDay) {
                var footer = document.createElement("div");
                footer.className = "flex justify-center mt-2";

                var todayBtn = document.createElement("button");
                todayBtn.type = "button";
                todayBtn.className = "btn btn-ghost btn-xs";
                todayBtn.textContent = "Today";
                todayBtn.addEventListener("click", function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    selectedDate = today;
                    viewYear = today.getFullYear();
                    viewMonth = today.getMonth();

                    if (input.classList.contains("themis-datetime-picker")) {
                        var timePart = "";
                        if (input.value) {
                            var spaceIdx = input.value.indexOf(" ");
                            if (spaceIdx > -1) {
                                timePart = input.value.substring(spaceIdx);
                            }
                        }
                        input.value = formatDate(today) + timePart;
                    } else {
                        input.value = formatDate(today);
                    }
                    input.dispatchEvent(new Event("change", { bubbles: true }));
                    closePopup();
                });
                footer.appendChild(todayBtn);

                // Clear button
                var clearBtn = document.createElement("button");
                clearBtn.type = "button";
                clearBtn.className = "btn btn-ghost btn-xs ml-2";
                clearBtn.textContent = "Clear";
                clearBtn.addEventListener("click", function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    input.value = "";
                    selectedDate = null;
                    input.dispatchEvent(new Event("change", { bubbles: true }));
                    closePopup();
                });
                footer.appendChild(clearBtn);

                popup.appendChild(footer);
            }
        }

        function closePopup() {
            if (popup.parentNode) {
                popup.parentNode.removeChild(popup);
            }
            document.removeEventListener("click", onDocumentClick, true);
            document.removeEventListener("keydown", onEscape, true);
        }

        function onDocumentClick(e) {
            if (!popup.contains(e.target) && e.target !== input) {
                closePopup();
            }
        }

        function onEscape(e) {
            if (e.key === "Escape") {
                closePopup();
            }
        }

        render();

        // Position relative to input
        var wrapper = input.parentNode;
        if (getComputedStyle(wrapper).position === "static") {
            wrapper.style.position = "relative";
        }
        wrapper.appendChild(popup);

        // Register close handlers after a tick to avoid immediate close
        setTimeout(function () {
            document.addEventListener("click", onDocumentClick, true);
            document.addEventListener("keydown", onEscape, true);
        }, 0);

        return { popup: popup, close: closePopup };
    }

    // ── Attach to inputs ─────────────────────────────────────────────

    function attachDatePicker(input, isMonthDay) {
        var activePopup = null;

        // Set placeholder
        if (!input.placeholder) {
            input.placeholder = isMonthDay ? "MM-DD" : dateFormat;
        }

        // Make input read-only to prevent keyboard on mobile, but allow tab
        input.setAttribute("readonly", "readonly");
        input.style.cursor = "pointer";

        // Format existing ISO value to display format on load
        if (!isMonthDay && input.value) {
            var parsed = parseDisplayDate(input.value);
            if (!parsed) {
                // Try parsing as ISO
                var isoParts = input.value.split("-");
                if (isoParts.length === 3) {
                    parsed = new Date(+isoParts[0], +isoParts[1] - 1, +isoParts[2]);
                    if (parsed && !isNaN(parsed.getTime())) {
                        if (input.classList.contains("themis-datetime-picker")) {
                            var timePart = "";
                            var spaceIdx = input.value.indexOf(" ");
                            if (spaceIdx > -1) {
                                timePart = input.value.substring(spaceIdx);
                            }
                            input.value = formatDate(parsed) + timePart;
                        } else {
                            input.value = formatDate(parsed);
                        }
                    }
                }
            }
        }

        input.addEventListener("click", function (e) {
            e.preventDefault();
            if (activePopup) {
                activePopup.close();
                activePopup = null;
                return;
            }
            activePopup = createPopup(input, isMonthDay);
        });

        input.addEventListener("focus", function () {
            if (!activePopup) {
                activePopup = createPopup(input, isMonthDay);
            }
        });
    }

    // ── Init ─────────────────────────────────────────────────────────

    document.querySelectorAll(".themis-date-picker").forEach(function (el) {
        attachDatePicker(el, false);
    });
    document.querySelectorAll(".themis-datetime-picker").forEach(function (el) {
        attachDatePicker(el, false);
    });
    document.querySelectorAll(".themis-monthday-picker").forEach(function (el) {
        attachDatePicker(el, true);
    });

})();
