<?php
/**
 * Antara — hardened PHP session helpers.
 *
 * - HttpOnly + SameSite=Lax (Strict on /admin) + Secure when HTTPS detected
 * - Custom session name (no PHPSESSID footprint)
 * - ID regenerated after authentication
 * - Idle-timeout enforcement against the per-request auth_config
 * - UA + IP fingerprint to mitigate session fixation/hijack
 */

if (!defined('ANTARA_ROOT')) {
    define('ANTARA_ROOT', dirname(__DIR__, 2));
}

final class AntaraSession
{
    public const COOKIE_NAME = 'antara_sid';

    public static function start(): void
    {
        if (session_status() === PHP_SESSION_ACTIVE) return;

        $isHttps = (
            (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
            || (($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https')
            || (($_SERVER['SERVER_PORT'] ?? '') === '443')
        );

        session_name(self::COOKIE_NAME);
        session_set_cookie_params([
            'lifetime' => 0,
            'path'     => '/',
            'domain'   => '',
            'secure'   => $isHttps,
            'httponly' => true,
            'samesite' => 'Lax',
        ]);
        ini_set('session.use_strict_mode', '1');
        ini_set('session.cookie_httponly', '1');
        ini_set('session.use_only_cookies', '1');

        session_start();

        if (empty($_SESSION['_fp'])) {
            $_SESSION['_fp'] = self::fingerprint();
            $_SESSION['_created_at'] = time();
        } elseif ($_SESSION['_fp'] !== self::fingerprint()) {
            $installActive = (int) ($_SESSION['install_wizard_active'] ?? 0);
            $installGrace = $installActive > 0
                && (time() - $installActive) < (defined('ANTARA_INSTALL_WIZARD_SESSION_GRACE_SEC')
                    ? ANTARA_INSTALL_WIZARD_SESSION_GRACE_SEC
                    : 604800);
            if (!$installGrace) {
                self::destroy();
                session_start();
                $_SESSION['_fp'] = self::fingerprint();
                $_SESSION['_created_at'] = time();
            }
        }
    }

    private static function fingerprint(): string
    {
        $ua = substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 256);
        // We pin the /24 of the IP only, to tolerate NAT/CDN drift.
        $ip = $_SERVER['REMOTE_ADDR'] ?? '';
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
            $parts = explode('.', $ip);
            $ip = $parts[0] . '.' . $parts[1] . '.' . $parts[2] . '.0';
        }
        return hash('sha256', $ua . '|' . $ip);
    }

    public static function login(array $user): void
    {
        self::start();
        session_regenerate_id(true);
        $_SESSION['user'] = [
            'id'    => $user['id'],
            'email' => $user['email'] ?? '',
            'username' => $user['username'] ?? '',
            'role'  => $user['role'] ?? 'usuario',
            'requirePasswordReset' => !empty($user['requirePasswordReset']),
        ];
        $_SESSION['_login_at'] = time();
        $_SESSION['_last_seen_at'] = time();
    }

    public static function user(): ?array
    {
        self::start();
        return $_SESSION['user'] ?? null;
    }

    public static function isLoggedIn(): bool
    {
        return self::user() !== null;
    }

    public static function touch(): void
    {
        self::start();
        if (isset($_SESSION['user'])) {
            $_SESSION['_last_seen_at'] = time();
        }
    }

    public static function isExpired(int $timeoutMinutes): bool
    {
        self::start();
        if (!isset($_SESSION['user'])) return false;
        $last = (int)($_SESSION['_last_seen_at'] ?? 0);
        if ($last <= 0) return false;
        return (time() - $last) > ($timeoutMinutes * 60);
    }

    public static function destroy(): void
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_name(self::COOKIE_NAME);
            @session_start();
        }
        $_SESSION = [];
        if (ini_get('session.use_cookies')) {
            $params = session_get_cookie_params();
            setcookie(session_name(), '', [
                'expires'  => time() - 42000,
                'path'     => $params['path'],
                'domain'   => $params['domain'],
                'secure'   => $params['secure'],
                'httponly' => $params['httponly'],
                'samesite' => $params['samesite'] ?? 'Lax',
            ]);
        }
        @session_destroy();
    }
}
