/*
 * Copyright 2026 Alessandro Chiapparini <sprint_planer_web@chiapparini.org>
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * See the LICENSE file in the project root for the full license text.
 */
/**
 * Site-wide behaviour. Three concerns:
 *   1. Vanilla-JS click delegation for [data-href] rows (sprint list).
 *   2. Alpine CSP component: appMenu (hamburger).
 *   3. Alpine CSP component: themeToggle (dark-mode flip).
 *
 * htmx is loaded site-wide and sends X-CSRF-Token automatically per the
 * `htmx:configRequest` listener below.
 */

(function () {
    'use strict';

    // ----- data-href click delegation ------------------------------------
    function navigate(el, ev) {
        const href = String(el.getAttribute('data-href') || '');
        if (href === '') { return; }
        if (ev.metaKey || ev.ctrlKey || ev.button === 1) {
            window.open(href, '_blank');
        } else {
            window.location.href = href;
        }
    }

    document.addEventListener('click', function (ev) {
        const el = ev.target.closest('[data-href]');
        if (!el) { return; }
        // Ignore clicks that originated on an interactive descendant.
        if (ev.target.closest('a, button, input, select, textarea, label')) { return; }
        navigate(el, ev);
    });

    document.addEventListener('keydown', function (ev) {
        if (ev.key !== 'Enter') { return; }
        const el = ev.target.closest('[data-href]');
        if (!el) { return; }
        if (ev.target.closest('a, button, input, select, textarea, label')) { return; }
        ev.preventDefault();
        window.location.href = String(el.getAttribute('data-href') || '');
    });

    // Make every data-href row keyboard-reachable + screenreader-friendly.
    document.querySelectorAll('[data-href]').forEach(function (el) {
        el.setAttribute('role', 'link');
        el.setAttribute('tabindex', '0');
    });

    // ----- htmx CSRF wiring ---------------------------------------------
    // The CSRF token lives on every layout's form (_csrf hidden input) and on
    // the [data-sprint-root] element (data-csrf). Pull from a hidden input if
    // present so non-sprint pages also get the header attached.
    function readCsrfToken() {
        const inp = document.querySelector('input[name="_csrf"]');
        if (inp && inp.value) { return inp.value; }
        const root = document.querySelector('[data-sprint-root]');
        if (root && root.getAttribute('data-csrf')) {
            return root.getAttribute('data-csrf');
        }
        return '';
    }

    document.addEventListener('htmx:configRequest', function (ev) {
        const tok = readCsrfToken();
        if (tok && ev.detail && ev.detail.headers) {
            ev.detail.headers['X-CSRF-Token'] = tok;
        }
    });

    // ----- Local-timezone datetime rendering ----------------------------
    // Server emits each audit row's `occurred_at` as a UTC ISO-8601 string
    // inside <time data-local-datetime datetime="…">…</time>. Rewrite the
    // text content to the viewer's local timezone in dd.mm.YYYY HH:mm:ss.
    function pad2(n) { return n < 10 ? '0' + n : '' + n; }
    function formatLocalDateTime(d) {
        return pad2(d.getDate()) + '.' + pad2(d.getMonth() + 1) + '.' + d.getFullYear()
            + ' ' + pad2(d.getHours()) + ':' + pad2(d.getMinutes()) + ':' + pad2(d.getSeconds());
    }
    function localizeDateTimes(root) {
        const scope = root || document;
        const els = scope.querySelectorAll('time[data-local-datetime]');
        els.forEach(function (el) {
            const iso = el.getAttribute('datetime') || '';
            if (iso === '') { return; }
            const d = new Date(iso);
            if (isNaN(d.getTime())) { return; }
            el.textContent = formatLocalDateTime(d);
        });
    }
    document.addEventListener('DOMContentLoaded', function () { localizeDateTimes(); });
    document.addEventListener('htmx:afterSwap', function (ev) {
        localizeDateTimes(ev.target || document);
    });

    // ----- Alpine component registrations -------------------------------
    document.addEventListener('alpine:init', function () {
        // Hamburger menu — toggle, close on outside / Escape / item click.
        window.Alpine.data('appMenu', function () {
            return {
                open: false,
                toggle()       { this.open = !this.open; },
                close()        { this.open = false; },
                closeAndFocus() {
                    if (!this.open) { return; }
                    this.open = false;
                    if (this.$refs.trigger) { this.$refs.trigger.focus(); }
                },
                closeOnItem(ev) {
                    if (ev.target.closest('[role="menuitem"]')) { this.open = false; }
                },
            };
        });

        // Theme toggle — flips <html class="dark">, persists in localStorage,
        // mirrors a "Dark" / "Light" label into the menu row.
        window.Alpine.data('themeToggle', function () {
            return {
                label: '',
                init() {
                    this.stamp();
                    // If theme-init.js loaded after Alpine for some reason,
                    // reflect the current class state on next tick.
                    this.$nextTick(() => this.stamp());
                },
                stamp() {
                    this.label = document.documentElement.classList.contains('dark') ? 'Dark' : 'Light';
                },
                flip() {
                    const nowDark = document.documentElement.classList.toggle('dark');
                    try { localStorage.setItem('sp:theme', nowDark ? 'dark' : 'light'); }
                    catch (e) { /* private mode quota — ignore */ }
                    this.stamp();
                },
            };
        });
    });
})();
