<?php
/**
 * Centralized Session Manager
 * Ensures consistent session configuration across the application
 */

class SessionManager
{
    private static $initialized = false;

    /**
     * Initialize session with consistent parameters
     */
    public static function initialize()
    {
        // Session already active (e.g. auto-start, or loaded before this call): mark ready
        if (session_status() === PHP_SESSION_ACTIVE) {
            self::$initialized = true;
            return;
        }

        if (self::$initialized || session_status() !== PHP_SESSION_NONE) {
            return;
        }

        // Set timezone before handling dates
        if (defined('TIMEZONE')) {
            date_default_timezone_set(TIMEZONE);
        }

        // Determine session lifetime
        $lifetime = self::getSessionLifetime();

        // Configure session parameters BEFORE session_start()
        ini_set('session.gc_maxlifetime', $lifetime);
        ini_set('session.cookie_lifetime', $lifetime);

        // Configure session cookies for security
        if (defined('SESSION_USE_COOKIES')) {
            ini_set('session.use_cookies', SESSION_USE_COOKIES ? 1 : 0);
        }

        // Set secure cookie parameters
        $secure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';

        $cookiePath = self::getCookiePath();
        session_name(self::getSessionCookieName());

        session_set_cookie_params([
            'lifetime' => $lifetime,
            'path' => $cookiePath,
            'domain' => self::getCookieDomain(),
            'secure' => $secure,
            'httponly' => true,
            'samesite' => 'Lax'
        ]);

        // Start the session
        session_start();

        // Set session expiry tracking
        self::setSessionExpiry($lifetime);

        self::$initialized = true;
    }

    /**
     * Get appropriate session lifetime based on remember me setting
     */
    private static function getSessionLifetime()
    {
        // Check if this is a "remember me" session
        $isRememberMe = isset($_SESSION['remember_me']) && $_SESSION['remember_me'];

        if ($isRememberMe) {
            return defined('SESSION_REMEMBER_ME_LIFETIME') ? SESSION_REMEMBER_ME_LIFETIME : 604800; // 1 week
        } else {
            return defined('SESSION_LIFETIME') ? SESSION_LIFETIME : 1440; // 24 minutes
        }
    }

    /**
     * Set session expiry timestamp for client-side tracking
     */
    private static function setSessionExpiry($lifetime)
    {
        try {
            $timezone = defined('TIMEZONE') ? TIMEZONE : 'UTC';
            $currentTime = new DateTime('now', new DateTimeZone($timezone));
            $expiryTime = clone $currentTime;
            $expiryTime->modify("+{$lifetime} seconds");
            $_SESSION['expires_at'] = $expiryTime->format('Y-m-d H:i:s T');
        } catch (Exception $e) {
            error_log("Session expiry calculation error: " . $e->getMessage());
            // Fallback to simple timestamp
            $_SESSION['expires_at'] = date('Y-m-d H:i:s T', time() + $lifetime);
        }
    }

    /**
     * Refresh session with new expiry time
     */
    public static function refresh()
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            $lifetime = self::getSessionLifetime();

            // Update session cookie expiry
            $secure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
            setcookie(
                session_name(),
                session_id(),
                [
                    'expires' => time() + $lifetime,
                    'path' => self::getCookiePath(),
                    'domain' => self::getCookieDomain(),
                    'secure' => $secure,
                    'httponly' => true,
                    'samesite' => 'Lax'
                ]
            );

            // Update session expiry tracking
            self::setSessionExpiry($lifetime);

            return true;
        }
        return false;
    }

    /**
     * Destroy session completely
     */
    public static function destroy()
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            // Clear session data
            $_SESSION = array();

            // Delete session cookie
            if (ini_get("session.use_cookies")) {
                $params = session_get_cookie_params();
                $secure = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';

                // 1. Clear cookie for the configured domain
                setcookie(session_name(), '', [
                    'expires' => time() - 42000,
                    'path' => $params["path"],
                    'domain' => $params["domain"],
                    'secure' => $secure,
                    'httponly' => $params["httponly"],
                    'samesite' => 'Lax'
                ]);

                // 2. Clear cookie for the host specifically (empty domain) to handle legacy duplicates
                if (!empty($params["domain"])) {
                    setcookie(session_name(), '', [
                        'expires' => time() - 42000,
                        'path' => $params["path"],
                        'domain' => '',
                        'secure' => $secure,
                        'httponly' => $params["httponly"],
                        'samesite' => 'Lax'
                    ]);
                }
            }

            // Destroy session
            session_destroy();
            self::$initialized = false;
        }
    }

    /**
     * Check if session is initialized
     */
    public static function isInitialized()
    {
        return self::$initialized;
    }

    /**
     * Validate session state and security
     */
    public static function validateSession()
    {
        if (!isset($_SESSION['user_id']) || !isset($_SESSION['role'])) {
            self::destroy();
            return false;
        }

        // Validate session expiry
        if (isset($_SESSION['expires_at'])) {
            try {
                $expiryTime = new DateTime($_SESSION['expires_at']);
                if ($expiryTime < new DateTime()) {
                    self::destroy();
                    return false;
                }
            } catch (Exception $e) {
                error_log("Session expiry validation error: " . $e->getMessage());
                return false;
            }
        }

        return true;
    }

    /**
     * Update session state version after critical changes
     */
    public static function updateSessionState()
    {
        if (!isset($_SESSION['user_id'])) {
            return false;
        }

        $_SESSION['state_version'] = hash('sha256', json_encode([
            'user_id' => $_SESSION['user_id'],
            'role' => $_SESSION['role'],
            'last_activity' => time()
        ]));

        return true;
    }

    /**
     * Cookie path scoped to this install (BASE_URL path), not the entire domain.
     * Strips trailing /fr and /de so language copies under the same product path share one session.
     * Override with define('SESSION_COOKIE_PATH', '/custom/path/'); in config if needed.
     */
    private static function getCookiePath()
    {
        if (defined('SESSION_COOKIE_PATH') && is_string(SESSION_COOKIE_PATH) && SESSION_COOKIE_PATH !== '') {
            $p = SESSION_COOKIE_PATH;
            return $p[0] === '/' ? $p : '/' . $p;
        }

        if (!defined('BASE_URL') || BASE_URL === '') {
            return '/';
        }

        $path = parse_url(BASE_URL, PHP_URL_PATH);
        if ($path === null || $path === '' || $path === '/') {
            return '/';
        }

        $path = rtrim($path, '/');
        $path = preg_replace('#/(fr|de)$#', '', $path);

        if ($path === '') {
            return '/';
        }

        return $path . '/';
    }

    /**
     * Distinct session cookie name per site path so other PHP apps on the same domain
     * cannot clobber PHPSESSID and break CSRF. Root + /fr + /de copies share one name.
     * Override with define('SESSION_NAME', 'MyApp'); in config if needed.
     */
    private static function getSessionCookieName()
    {
        if (defined('SESSION_NAME') && is_string(SESSION_NAME) && SESSION_NAME !== '') {
            return SESSION_NAME;
        }

        if (!defined('BASE_URL') || BASE_URL === '') {
            return 'PHPSESSID';
        }

        $host = parse_url(BASE_URL, PHP_URL_HOST);
        $host = $host ? strtolower($host) : '';
        $path = parse_url(BASE_URL, PHP_URL_PATH);
        $path = ($path !== null && $path !== '') ? rtrim($path, '/') : '';
        $path = preg_replace('#/(fr|de)$#', '', $path);

        $key = $host . '|' . $path;
        return 'SE' . substr(hash('sha256', $key), 0, 16);
    }

    /**
     * Get consistent cookie domain for session management
     */
    private static function getCookieDomain()
    {
        if (!defined('BASE_URL') || empty(BASE_URL)) {
            return '';
        }

        $parsed_url = parse_url(BASE_URL);
        if (!isset($parsed_url['host'])) {
            return '';
        }

        $host = $parsed_url['host'];
        // Remove port if present
        $host = preg_replace('/:\d+$/', '', $host);

        // For localhost/127.0.0.1/IPs, leave domain empty to avoid browser rejection
        if ($host === 'localhost' || $host === '127.0.0.1' || filter_var($host, FILTER_VALIDATE_IP)) {
            return '';
        }

        // Extract domain (e.g., '.example.com' from 'www.example.com')
        $parts = explode('.', $host);
        if (count($parts) >= 2) {
            // Use last two parts for domain
            return '.' . implode('.', array_slice($parts, -2));
        }

        return $host;
    }
}