<?php
/**
 * RUHONDO BEACH RESORT HMS + POS System
 * CSRF Protection Functions - COMPLETE FIXED VERSION
 * Developer: JOACHIM'S INNOTECH
 */

// Prevent direct access
if (!defined('BASE_PATH')) {
    exit('Direct access not permitted');
}

// Ensure session is started
if (session_status() === PHP_SESSION_NONE) {
    session_start();
}

/**
 * Generate a new CSRF token
 * 
 * @param bool $regenerate Whether to regenerate the token
 * @return string The CSRF token
 */
if (!function_exists('generate_csrf_token')) {
    function generate_csrf_token($regenerate = false) {
        if (!isset($_SESSION['csrf_tokens'])) {
            $_SESSION['csrf_tokens'] = [];
        }
        
        // Clean up expired tokens (older than 2 hours)
        $expiry_time = time() - 7200; // 2 hours
        foreach ($_SESSION['csrf_tokens'] as $token => $time) {
            if ($time < $expiry_time) {
                unset($_SESSION['csrf_tokens'][$token]);
            }
        }
        
        // Generate new token if needed
        if ($regenerate || empty($_SESSION['csrf_tokens'])) {
            $token = bin2hex(random_bytes(32));
            $_SESSION['csrf_tokens'][$token] = time();
            return $token;
        }
        
        // Return the most recent token
        end($_SESSION['csrf_tokens']);
        return key($_SESSION['csrf_tokens']);
    }
}

/**
 * Get the current CSRF token
 * 
 * @return string The current CSRF token
 */
if (!function_exists('csrf_token')) {
    function csrf_token() {
        return generate_csrf_token();
    }
}

/**
 * Generate a CSRF field for forms
 * 
 * @return string HTML input field with CSRF token
 */
if (!function_exists('csrf_field')) {
    function csrf_field() {
        $token = generate_csrf_token();
        $csrf_name = defined('CSRF_TOKEN_NAME') ? CSRF_TOKEN_NAME : 'csrf_token';
        return '<input type="hidden" name="' . htmlspecialchars($csrf_name, ENT_QUOTES, 'UTF-8') . '" value="' . htmlspecialchars($token, ENT_QUOTES, 'UTF-8') . '">';
    }
}

/**
 * Generate CSRF meta tags for HTML head
 * 
 * @return string HTML meta tags
 */
if (!function_exists('csrf_meta_tags')) {
    function csrf_meta_tags() {
        $token = generate_csrf_token();
        $csrf_name = defined('CSRF_TOKEN_NAME') ? CSRF_TOKEN_NAME : 'csrf_token';
        return '<meta name="csrf-token" content="' . htmlspecialchars($token, ENT_QUOTES, 'UTF-8') . '">' . "\n" .
               '<meta name="csrf-param" content="' . htmlspecialchars($csrf_name, ENT_QUOTES, 'UTF-8') . '">';
    }
}

/**
 * Verify CSRF token
 * 
 * @param string $token The token to verify
 * @return bool True if token is valid, false otherwise
 */
if (!function_exists('verify_csrf_token')) {
    function verify_csrf_token($token) {
        if (empty($token) || !isset($_SESSION['csrf_tokens'])) {
            return false;
        }
        
        // Check if token exists and is not expired
        if (isset($_SESSION['csrf_tokens'][$token])) {
            $token_time = $_SESSION['csrf_tokens'][$token];
            $current_time = time();
            
            // Token expires after 2 hours
            if (($current_time - $token_time) <= 7200) {
                // Remove used token (one-time use)
                unset($_SESSION['csrf_tokens'][$token]);
                return true;
            } else {
                // Remove expired token
                unset($_SESSION['csrf_tokens'][$token]);
            }
        }
        
        return false;
    }
}

/**
 * Verify CSRF token from request
 * 
 * @param string $method Request method to check (POST, GET, etc.)
 * @return bool True if token is valid, false otherwise
 */
if (!function_exists('verify_csrf_request')) {
    function verify_csrf_request($method = 'POST') {
        $token = null;
        $csrf_name = defined('CSRF_TOKEN_NAME') ? CSRF_TOKEN_NAME : 'csrf_token';
        
        switch (strtoupper($method)) {
            case 'POST':
                $token = $_POST[$csrf_name] ?? null;
                break;
            case 'GET':
                $token = $_GET[$csrf_name] ?? null;
                break;
            case 'HEADER':
                $headers = function_exists('getallheaders') ? getallheaders() : [];
                $token = $headers['X-CSRF-Token'] ?? $headers['X-CSRF-TOKEN'] ?? null;
                break;
        }
        
        return verify_csrf_token($token);
    }
}

/**
 * Require valid CSRF token or exit with error
 * 
 * @param string $method Request method to check
 */
if (!function_exists('require_valid_csrf')) {
    function require_valid_csrf($method = 'POST') {
        if (!verify_csrf_request($method)) {
            if (function_exists('is_ajax_request') && is_ajax_request()) {
                if (function_exists('json_error')) {
                    json_error('Invalid CSRF token. Please refresh the page and try again.', null, 403);
                } else {
                    http_response_code(403);
                    header('Content-Type: application/json');
                    echo json_encode([
                        'status' => 'error',
                        'message' => 'Invalid CSRF token. Please refresh the page and try again.'
                    ]);
                    exit;
                }
            } else {
                if (function_exists('set_flash_message')) {
                    set_flash_message('danger', 'Invalid security token. Please try again.');
                }
                if (function_exists('redirect_back')) {
                    redirect_back();
                } else {
                    header('Location: ' . ($_SERVER['HTTP_REFERER'] ?? 'index.php'));
                    exit;
                }
            }
            exit;
        }
    }
}

/**
 * Initialize CSRF protection
 * Call this at the beginning of each request
 */
if (!function_exists('init_csrf_protection')) {
    function init_csrf_protection() {
        // Generate initial token if none exists
        if (!isset($_SESSION['csrf_tokens']) || empty($_SESSION['csrf_tokens'])) {
            generate_csrf_token(true);
        }
    }
}

// Initialize CSRF protection
init_csrf_protection();