<?php
/**
 * Security Helper
 * CSRF Protection, XSS Escaping, Security Headers, Password Hashing, and Token Generation
 */

class Security {
    /**
     * Apply Standard Security Headers to HTTP Response
     */
    public static function applySecurityHeaders(): void {
        if (headers_sent()) {
            return;
        }

        $securityConfig = file_exists(__DIR__ . '/../../config/security.php')
            ? require __DIR__ . '/../../config/security.php'
            : [];
        $headers = $securityConfig['headers'] ?? [
            'X-Content-Type-Options' => 'nosniff',
            'X-Frame-Options'        => 'SAMEORIGIN',
            'X-XSS-Protection'       => '1; mode=block',
            'Referrer-Policy'        => 'strict-origin-when-cross-origin'
        ];

        foreach ($headers as $name => $val) {
            header("{$name}: {$val}");
        }
    }

    /**
     * Generate or return existing CSRF token
     */
    public static function csrfToken(): string {
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }

    /**
     * Return hidden HTML input for CSRF
     */
    public static function csrfField(): string {
        $token = self::csrfToken();
        return '<input type="hidden" name="csrf_token" value="' . self::escape($token) . '">';
    }

    /**
     * Verify CSRF token with constant-time string comparison
     */
    public static function verifyCsrfToken(?string $token): bool {
        if (empty($token) || empty($_SESSION['csrf_token'])) {
            return false;
        }
        return hash_equals($_SESSION['csrf_token'], $token);
    }

    /**
     * XSS Output Escaping
     */
    public static function escape(?string $value): string {
        if ($value === null) {
            return '';
        }
        return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
    }

    /**
     * Sanitize string input
     */
    public static function sanitizeString(?string $input): string {
        if ($input === null) {
            return '';
        }
        return trim(strip_tags($input));
    }

    /**
     * Standardized Password Hashing (BCRYPT cost 12)
     */
    public static function hashPassword(string $password): string {
        return password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);
    }

    /**
     * Verify Password
     */
    public static function verifyPassword(string $password, string $hash): bool {
        return password_verify($password, $hash);
    }

    /**
     * Generate Secure Cryptographic Token
     */
    public static function generateToken(int $length = 32): string {
        return bin2hex(random_bytes($length));
    }

    /**
     * Hash Token for Safe Storage in Database (SHA-256)
     */
    public static function hashToken(string $token): string {
        return hash('sha256', $token);
    }

    /**
     * Get Client IP Address safely
     */
    public static function getClientIp(): string {
        $ip = $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1';
        if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
            $ip = $_SERVER['HTTP_CLIENT_IP'];
        } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
            $ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $ip = trim($ips[0]);
        }
        return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '127.0.0.1';
    }

    /**
     * Get Client User Agent safely
     */
    public static function getUserAgent(): string {
        $ua = $_SERVER['HTTP_USER_AGENT'] ?? 'Unknown Device';
        return mb_substr(trim($ua), 0, 500);
    }
}

/**
 * Global shorthand for XSS escaping
 */
function e(?string $value): string {
    return Security::escape($value);
}
