'use strict';

const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

const root = __dirname;
const read = (file) => fs.readFileSync(path.join(root, file), 'utf8');
const results = [];
let failures = 0;

function check(name, condition, detail = '') {
    const passed = Boolean(condition);
    if (!passed) failures += 1;
    results.push({ status: passed ? 'PASS' : 'FAIL', name, detail });
}

const config = read('config.example.php');
const bootstrap = read('app/bootstrap.php');
const session = read('app/session.php');
const header = read('app/header.php');
const footer = read('app/footer.php');
const login = read('login.php');
const logout = read('logout.php');
const activity = read('session_activity.php');
const extend = read('session_extend.php');
const js = read('assets/js/session-timeout.js');
const css = read('assets/css/style.css');
const database = fs.readFileSync(path.join(root, 'database.sql'));
const dump = fs.readFileSync(path.join(root, 'sosmthhg_infratest.sql'));

check('Centralna konfiguracija koristi 600/60 sekundi',
    config.includes("define('APP_SESSION_IDLE_SECONDS', 600)") &&
    config.includes("define('APP_SESSION_WARNING_SECONDS', 60)") &&
    config.includes("define('APP_SESSION_ACTIVITY_THROTTLE_SECONDS', 60)"));
check('Bootstrap više ne osvežava sesiju na svakom zahtevu',
    !bootstrap.includes("$_SESSION['last_activity'] = time()") &&
    bootstrap.includes('request_represents_user_navigation()'));
check('Background AJAX, JSON i prefetch zahtevi su isključeni',
    session.includes("$requestedWith === 'xmlhttprequest'") &&
    session.includes("str_contains($accept, 'application/json')") &&
    session.includes("str_contains($purpose, 'prefetch')"));
check('Serverski hard timeout je zbir 10 minuta i upozorenja',
    session.includes('session_idle_timeout_seconds() + session_warning_duration_seconds()') &&
    session.includes('>= session_hard_timeout_seconds()'));
check('Login kreira čistu oznaku nove sesije',
    login.includes("$_SESSION['session_started_at']") &&
    login.includes("unset($_SESSION['session_expiry_notice_queued'])"));
check('Timer se učitava samo za autentifikovanog korisnika',
    header.includes('if ($sessionTimeoutEnabled)') &&
    header.includes('assets/js/session-timeout.js') &&
    header.includes('data-session-timeout="enabled"'));
check('Login i javne stranice nemaju modal bez korisnika',
    footer.includes("if (!empty($user))") &&
    footer.includes('id="sessionWarningModal"'));
check('Modal ima tačan tekst, 60-sekundni brojač i obe akcije',
    footer.includes('Da li još uvek radite na sistemu?') &&
    footer.includes('sessionWarningRemainingSeconds') &&
    footer.includes('Produži rad') && footer.includes('Odjava'));
check('Modal je zaključan i pozadina blokirana',
    js.includes("event.key === 'Escape'") && js.includes('event.stopImmediatePropagation()') &&
    css.includes('body.session-warning-open > *:not(.session-timeout-backdrop)') &&
    css.includes('pointer-events: none'));
check('Stvarna aktivnost ne koristi mousemove i ima throttling',
    !js.includes('mousemove') &&
    js.includes("addEventListener('pointerdown'") &&
    js.includes("addEventListener('keydown'") &&
    js.includes("addEventListener('input'") &&
    js.includes('activityThrottleMs'));
check('Produženje i evidentiranje aktivnosti koriste POST, CSRF i same-origin',
    activity.includes("REQUEST_METHOD") && activity.includes("!== 'POST'") && activity.includes('csrf_token_is_valid') &&
    extend.includes("REQUEST_METHOD") && extend.includes("!== 'POST'") && extend.includes('csrf_token_is_valid') &&
    js.includes("credentials: 'same-origin'") && js.includes("method: 'POST'"));
check('Logout ostaje centralizovan u logout.php',
    js.includes('config.logoutUrl') && logout.includes('invalidate_current_session()') &&
    !activity.includes('invalidate_current_session()') && !extend.includes('invalidate_current_session()'));
check('401 odgovor pokreće kontrolisanu odjavu',
    js.includes('response.status === 401') && js.includes("terminateSession('expired')"));
check('Više tabova koristi BroadcastChannel i storage fallback',
    js.includes("'BroadcastChannel' in window") &&
    js.includes("addEventListener('storage'") &&
    js.includes("message.type === 'extended'") && js.includes("message.type === 'logout'"));
check('U localStorage se ne upisuju lozinke, session ID ili CSRF token',
    !/localStorage[^\n]*(password|session[_-]?id|csrf|token)/i.test(js) &&
    !/safeStorageSet\([^\n]*(csrf|token|password)/i.test(js));
check('Sleep/hidden-tab povratak odmah preračunava rok',
    js.includes("addEventListener('visibilitychange', evaluateTimeout)") &&
    js.includes("addEventListener('focus', evaluateTimeout)") &&
    js.includes("addEventListener('pageshow', evaluateTimeout)"));
check('Event listener/tajmeri imaju cleanup',
    js.includes("addEventListener('pagehide', destroy") &&
    js.includes('clearInterval(tickTimer)') && js.includes('clearTimeout(activitySyncTimer)'));
check('Responsive CSS postoji bez izmene globalnog layout-a',
    css.includes('.session-timeout-backdrop') && css.includes('@media (max-width: 520px)') &&
    css.includes('.session-timeout-actions { grid-template-columns: 1fr; }'));
check('SQL fajlovi nemaju session tabelu ili migraciju',
    !/CREATE TABLE[^;]*session/i.test(database.toString('utf8')) &&
    !/CREATE TABLE[^;]*session/i.test(dump.toString('utf8')),
    `${crypto.createHash('sha256').update(database).digest('hex').slice(0, 12)} / ${crypto.createHash('sha256').update(dump).digest('hex').slice(0, 12)}`);

for (const result of results) {
    console.log(`${result.status.padEnd(4)} | ${result.name}${result.detail ? ` | ${result.detail}` : ''}`);
}
console.log(`\nUKUPNO: ${results.length - failures}/${results.length} PASS`);
process.exitCode = failures === 0 ? 0 : 1;
