<?php
/**
 * Security Helper Functions
 * CSRF protection, session security, and other security utilities
 */

/**
 * Initialize secure session configuration
 * Call this before session_start()
 */
function initSecureSession() {
    // Prevent session fixation
    ini_set('session.use_strict_mode', 1);

    // Use cookies only (not URL)
    ini_set('session.use_only_cookies', 1);
    ini_set('session.use_trans_sid', 0);

    // Make cookies HTTP only (prevent XSS)
    ini_set('session.cookie_httponly', 1);

    // Use secure cookies if on HTTPS
    if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') {
        ini_set('session.cookie_secure', 1);
    }

    // Set SameSite to Strict (prevent CSRF)
    ini_set('session.cookie_samesite', 'Strict');

    // Increase session lifetime to 24 hours
    ini_set('session.gc_maxlifetime', 86400);
}

/**
 * Generate CSRF token for forms
 * @return string The generated token
 */
function generateCSRFToken() {
    if (!isset($_SESSION['csrf_token'])) {
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
    }
    return $_SESSION['csrf_token'];
}

/**
 * Validate CSRF token from form submission
 * @param string $token The token to validate
 * @return bool True if valid, false otherwise
 */
function validateCSRFToken($token) {
    if (!isset($_SESSION['csrf_token'])) {
        return false;
    }
    return hash_equals($_SESSION['csrf_token'], $token);
}

/**
 * Get CSRF token input field HTML
 * @return string HTML input field
 */
function csrfField() {
    $token = generateCSRFToken();
    return '<input type="hidden" name="csrf_token" value="' . htmlspecialchars($token) . '">';
}

/**
 * Check if CSRF token is valid in POST request
 * Dies with error if invalid
 */
function requireCSRFToken() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $token = $_POST['csrf_token'] ?? '';
        if (!validateCSRFToken($token)) {
            http_response_code(403);
            die('CSRF token validation failed. Please try again.');
        }
    }
}

/**
 * Sanitize user input
 * @param string $data The data to sanitize
 * @return string Sanitized data
 */
function sanitizeInput($data) {
    $data = trim($data);
    $data = stripslashes($data);
    $data = htmlspecialchars($data, ENT_QUOTES, 'UTF-8');
    return $data;
}

/**
 * Validate invitation token
 * @param mysqli $conn Database connection
 * @param string $token The token to validate
 * @param string $expected_type Expected user type (instructor/admin)
 * @return array|false Token data if valid, false otherwise
 */
function validateInvitationToken($conn, $token, $expected_type) {
    $stmt = $conn->prepare("
        SELECT * FROM invitation_tokens
        WHERE token = ?
        AND user_type = ?
        AND is_active = 1
        AND use_count < max_uses
        AND (expires_at IS NULL OR expires_at > NOW())
    ");
    $stmt->bind_param("ss", $token, $expected_type);
    $stmt->execute();
    $result = $stmt->get_result();

    if ($result->num_rows > 0) {
        $token_data = $result->fetch_assoc();
        $stmt->close();
        return $token_data;
    }

    $stmt->close();
    return false;
}

/**
 * Mark invitation token as used
 * @param mysqli $conn Database connection
 * @param string $token The token
 * @param int $user_id The ID of the user who used it
 * @return bool Success
 */
function markTokenUsed($conn, $token, $user_id) {
    $stmt = $conn->prepare("
        UPDATE invitation_tokens
        SET use_count = use_count + 1,
            used_by = ?,
            used_at = NOW()
        WHERE token = ?
    ");
    $stmt->bind_param("is", $user_id, $token);
    $success = $stmt->execute();
    $stmt->close();
    return $success;
}

/**
 * Set security headers
 */
function setSecurityHeaders() {
    // Prevent clickjacking
    header("X-Frame-Options: DENY");

    // Prevent MIME sniffing
    header("X-Content-Type-Options: nosniff");

    // Enable XSS protection
    header("X-XSS-Protection: 1; mode=block");

    // Referrer policy
    header("Referrer-Policy: strict-origin-when-cross-origin");

    // Content Security Policy (adjust as needed)
    // Commented out by default as it may break inline scripts/styles
    // header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'");
}

/**
 * Validate password strength
 * @param string $password The password to validate
 * @return array ['valid' => bool, 'errors' => array]
 */
function validatePasswordStrength($password) {
    $errors = [];

    if (strlen($password) < 8) {
        $errors[] = "Password must be at least 8 characters long";
    }

    if (!preg_match('/[A-Z]/', $password)) {
        $errors[] = "Password must contain at least one uppercase letter";
    }

    if (!preg_match('/[a-z]/', $password)) {
        $errors[] = "Password must contain at least one lowercase letter";
    }

    if (!preg_match('/[0-9]/', $password)) {
        $errors[] = "Password must contain at least one number";
    }

    // Optional: require special character
    // if (!preg_match('/[^A-Za-z0-9]/', $password)) {
    //     $errors[] = "Password must contain at least one special character";
    // }

    return [
        'valid' => empty($errors),
        'errors' => $errors
    ];
}

/**
 * Regenerate session ID to prevent session fixation
 */
function regenerateSession() {
    if (session_status() === PHP_SESSION_ACTIVE) {
        session_regenerate_id(true);
    }
}
?>
