<?php
if (session_status() !== PHP_SESSION_ACTIVE) {
    session_start();
}

if (!defined('SESSION_IDLE_TIMEOUT')) {
    define('SESSION_IDLE_TIMEOUT', 600);
}

if (!defined('SESSION_WARNING_DURATION')) {
    define('SESSION_WARNING_DURATION', 60);
}

function sendNoCacheHeaders() {
    header('Expires: Tue, 01 Jan 2000 00:00:00 GMT');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
    header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
    header('Cache-Control: post-check=0, pre-check=0', false);
    header('Pragma: no-cache');
}

function isSessionExpired() {
    if (empty($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
        return false;
    }

    $last_activity = (int) ($_SESSION['last_activity'] ?? 0);
    if ($last_activity <= 0) {
        $_SESSION['last_activity'] = time();
        return false;
    }

    return (time() - $last_activity) > SESSION_IDLE_TIMEOUT;
}

function destroyActiveSession() {
    $_SESSION = [];

    if (ini_get('session.use_cookies')) {
        $params = session_get_cookie_params();
        setcookie(
            session_name(),
            '',
            time() - 42000,
            $params['path'],
            $params['domain'],
            $params['secure'],
            $params['httponly']
        );
    }

    session_destroy();
}

function redirectToLogin($reason = 'unauthorized') {
    header('Location: login.php?session=' . urlencode($reason));
    exit();
}

function isAccessPreviewRequest() {
    return ($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'GET'
        && isset($_GET['access_preview'])
        && (string) $_GET['access_preview'] === '1';
}

function requireLogin($conn = null, $roles = null) {
    sendNoCacheHeaders();

    if (empty($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
        redirectToLogin('unauthorized');
    }

    if (isSessionExpired()) {
        if ($conn && function_exists('logActivity') && isset($_SESSION['user_id'])) {
            logActivity($conn, $_SESSION['user_id'], 'auto_logout', 'Sesi tamat selepas 10 minit tidak aktif');
        }

        destroyActiveSession();
        redirectToLogin('expired');
    }

    if (is_array($roles) && !in_array($_SESSION['role'] ?? '', $roles, true)) {
        if (isAccessPreviewRequest()) {
            $_SESSION['access_preview_active'] = true;
            $_SESSION['access_preview_menu'] = trim((string) ($_GET['access_menu'] ?? 'bahagian ini'));
            return;
        }

        redirectToLogin('unauthorized');
    }

    $_SESSION['last_activity'] = time();
}

function renderSessionTimeoutScript() {
    if (empty($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
        return;
    }

    $idleTimeoutMs = SESSION_IDLE_TIMEOUT * 1000;
    $warningDurationMs = SESSION_WARNING_DURATION * 1000;
    $pingUrl = 'session_ping.php';
    $logoutUrl = 'logout.php?reason=timeout';

    echo <<<HTML
<script>
    (function () {
        const scrollKey = 'sistemFail.sidebar.scrollTop';
        const dropdownKey = 'sistemFail.sidebar.openDropdown';
        const noAutoOpenDropdowns = ['Pengurusan Pengguna'];

        function storageGet(key) {
            try { return window.localStorage.getItem(key); } catch (e) { return null; }
        }

        function storageSet(key, value) {
            try { window.localStorage.setItem(key, value); } catch (e) {}
        }

        function initSidebarState() {
            const sidebar = document.getElementById('sidebar');
            if (!sidebar || sidebar.dataset.sidebarStateReady === '1') {
                return;
            }

            sidebar.dataset.sidebarStateReady = '1';

            const restoreScroll = function () {
                const savedTop = parseInt(storageGet(scrollKey) || '0', 10);
                if (!Number.isNaN(savedTop) && savedTop > 0) {
                    sidebar.scrollTop = savedTop;
                    return;
                }

                const activeItem = sidebar.querySelector('.dropdown.active, a.active');
                if (activeItem && typeof activeItem.scrollIntoView === 'function') {
                    activeItem.scrollIntoView({ block: 'nearest' });
                    storageSet(scrollKey, String(sidebar.scrollTop));
                }
            };

            const restoreDropdown = function () {
                if (sidebar.querySelector('.dropdown.active')) {
                    return;
                }

                const savedDropdown = storageGet(dropdownKey);
                if (!savedDropdown || noAutoOpenDropdowns.includes(savedDropdown)) {
                    if (noAutoOpenDropdowns.includes(savedDropdown)) {
                        storageSet(dropdownKey, '');
                    }
                    return;
                }

                sidebar.querySelectorAll('.dropdown').forEach(function (dropdown) {
                    const toggle = dropdown.querySelector('.dropdown-toggle');
                    if (toggle && toggle.dataset.label === savedDropdown) {
                        dropdown.classList.add('active');
                        toggle.classList.add('active');
                    }
                });
            };

            const saveOpenDropdown = function () {
                const openDropdown = sidebar.querySelector('.dropdown.active .dropdown-toggle');
                const openLabel = openDropdown ? (openDropdown.dataset.label || '') : '';
                storageSet(dropdownKey, noAutoOpenDropdowns.includes(openLabel) ? '' : openLabel);
            };

            restoreDropdown();
            restoreScroll();
            window.requestAnimationFrame(restoreScroll);
            window.setTimeout(restoreScroll, 120);

            let scrollTimer = null;
            sidebar.addEventListener('scroll', function () {
                window.clearTimeout(scrollTimer);
                scrollTimer = window.setTimeout(function () {
                    storageSet(scrollKey, String(sidebar.scrollTop));
                }, 80);
            });

            sidebar.addEventListener('click', function (event) {
                const beforeTop = sidebar.scrollTop;
                const clickedDropdown = event.target.closest('.dropdown-toggle');
                const clickedLink = event.target.closest('a[href]');

                if (clickedLink) {
                    storageSet(scrollKey, String(beforeTop));
                }

                if (clickedDropdown) {
                    window.requestAnimationFrame(function () {
                        sidebar.scrollTop = beforeTop;
                        storageSet(scrollKey, String(sidebar.scrollTop));
                        saveOpenDropdown();
                    });
                }
            }, true);
        }

        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initSidebarState);
        } else {
            initSidebarState();
        }
    })();

    (function () {
        const idleTimeoutMs = {$idleTimeoutMs};
        const warningDurationMs = {$warningDurationMs};
        const keepAliveUrl = '{$pingUrl}';
        const logoutUrl = '{$logoutUrl}';
        const keepAliveThrottleMs = 60000;

        let lastActivityAt = Date.now();
        let lastKeepAliveAt = Date.now();
        let warningTimer = null;
        let logoutTimer = null;
        let countdownTimer = null;
        let warningVisible = false;

        const modal = document.createElement('div');
        modal.id = 'session-timeout-modal';
        modal.style.cssText = [
            'position:fixed',
            'inset:0',
            'background:rgba(15,23,42,0.45)',
            'display:none',
            'align-items:center',
            'justify-content:center',
            'padding:20px',
            'z-index:99999'
        ].join(';');

        modal.innerHTML = `
            <div style="width:min(420px,100%);background:#fff;border-radius:16px;padding:24px;box-shadow:0 20px 50px rgba(0,0,0,0.18);font-family:'Segoe UI','Inter',Tahoma,Geneva,Verdana,sans-serif;color:#1a3a5c;">
                <div style="display:flex;align-items:center;gap:12px;margin-bottom:12px;">
                    <div style="width:44px;height:44px;border-radius:50%;display:flex;align-items:center;justify-content:center;background:#fff3cd;color:#856404;font-size:20px;">!</div>
                    <div>
                        <div style="font-size:1.05rem;font-weight:700;">Amaran Sesi</div>
                        <div style="font-size:0.9rem;color:#6c757d;">Sesi anda akan ditamatkan tidak lama lagi.</div>
                    </div>
                </div>
                <p style="margin:0 0 18px;line-height:1.6;font-size:0.95rem;">
                    Anda tidak aktif. Sistem akan log keluar secara automatik dalam
                    <strong id="session-timeout-countdown">60</strong> saat.
                </p>
                <div style="display:flex;gap:10px;justify-content:flex-end;flex-wrap:wrap;">
                    <button type="button" id="session-logout-now" style="border:none;border-radius:10px;padding:11px 16px;background:#e9ecef;color:#495057;font-weight:600;cursor:pointer;">Log Keluar</button>
                    <button type="button" id="session-stay-login" style="border:none;border-radius:10px;padding:11px 16px;background:linear-gradient(90deg,#0077b6,#00b4d8);color:#fff;font-weight:700;cursor:pointer;">Kekal Log Masuk</button>
                </div>
            </div>
        `;

        document.addEventListener('DOMContentLoaded', function () {
            document.body.appendChild(modal);

            document.getElementById('session-stay-login').addEventListener('click', function () {
                registerActivity(true);
            });

            document.getElementById('session-logout-now').addEventListener('click', function () {
                window.location.href = 'logout.php?reason=manual';
            });
        });

        function clearTimers() {
            clearTimeout(warningTimer);
            clearTimeout(logoutTimer);
            clearInterval(countdownTimer);
        }

        function updateCountdown() {
            const secondsLeft = Math.max(0, Math.ceil((idleTimeoutMs - (Date.now() - lastActivityAt)) / 1000));
            const countdownEl = document.getElementById('session-timeout-countdown');
            if (countdownEl) {
                countdownEl.textContent = String(secondsLeft);
            }
        }

        function hideWarning() {
            warningVisible = false;
            modal.style.display = 'none';
            clearInterval(countdownTimer);
            countdownTimer = null;
        }

        function showWarning() {
            warningVisible = true;
            modal.style.display = 'flex';
            updateCountdown();
            clearInterval(countdownTimer);
            countdownTimer = setInterval(updateCountdown, 1000);
        }

        function scheduleTimers() {
            clearTimers();

            const elapsed = Date.now() - lastActivityAt;
            const untilWarning = Math.max(0, idleTimeoutMs - warningDurationMs - elapsed);
            const untilLogout = Math.max(0, idleTimeoutMs - elapsed);

            warningTimer = setTimeout(showWarning, untilWarning);
            logoutTimer = setTimeout(forceLogout, untilLogout);
        }

        function forceLogout() {
            window.location.href = logoutUrl;
        }

        function sendKeepAlive() {
            lastKeepAliveAt = Date.now();

            fetch(keepAliveUrl, {
                method: 'POST',
                headers: { 'X-Requested-With': 'XMLHttpRequest' },
                credentials: 'same-origin'
            }).then(function (response) {
                if (response.status === 401) {
                    forceLogout();
                }
            }).catch(function () {
                // Abaikan ralat rangkaian kecil; semakan server akan tetap berlaku pada request seterusnya.
            });
        }

        function registerActivity(forceKeepAlive) {
            lastActivityAt = Date.now();

            if (warningVisible) {
                hideWarning();
            }

            scheduleTimers();

            if (forceKeepAlive || (Date.now() - lastKeepAliveAt) >= keepAliveThrottleMs) {
                sendKeepAlive();
            }
        }

        let lastTrackedEventAt = 0;
        function handleActivity() {
            const now = Date.now();
            if ((now - lastTrackedEventAt) < 1000) {
                return;
            }

            lastTrackedEventAt = now;
            registerActivity(false);
        }

        ['click', 'keydown', 'mousemove', 'scroll', 'touchstart'].forEach(function (eventName) {
            window.addEventListener(eventName, handleActivity, { passive: true });
        });

        document.addEventListener('visibilitychange', function () {
            if (document.visibilityState === 'visible') {
                registerActivity(false);
            }
        });

        window.addEventListener('pageshow', function (event) {
            if (event.persisted) {
                window.location.reload();
            }
        });

        scheduleTimers();
    })();
</script>
HTML;
}

sendNoCacheHeaders();
?>
