<?php
/**
 * SalonPro X - Security Handler
 * CSRF protection, XSS prevention, input sanitization, encryption
 */

namespace core;

class Security
{
    /**
     * Generate CSRF token and store in session
     */
    public static function generateCsrfToken(): string
    {
        $token = bin2hex(random_bytes(32));
        Session::set('csrf_token', $token);
        return $token;
    }

    /**
     * Validate CSRF token from request
     */
    public static function validateCsrfToken(?string $token): bool
    {
        if (empty($token)) {
            return false;
        }
        $storedToken = Session::get('csrf_token');
        if (empty($storedToken)) {
            return false;
        }
        return hash_equals($storedToken, $token);
    }

    /**
     * Get CSRF token (generate if not exists)
     */
    public static function getCsrfToken(): string
    {
        $token = Session::get('csrf_token');
        if (empty($token)) {
            $token = self::generateCsrfToken();
        }
        return $token;
    }

    /**
     * Generate hidden CSRF input field
     */
    public static function csrfField(): string
    {
        $token = self::getCsrfToken();
        return '<input type="hidden" name="' . CSRF_TOKEN_NAME . '" value="' . $token . '">';
    }

    /**
     * Escape output for HTML (XSS prevention)
     */
    public static function escape(mixed $value): string
    {
        if ($value === null) {
            return '';
        }
        return htmlspecialchars((string)$value, ENT_QUOTES | ENT_HTML5, 'UTF-8', false);
    }

    /**
     * Escape for JavaScript string
     */
    public static function escapeJs(string $value): string
    {
        return json_encode($value, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
    }

    /**
     * Sanitize input string - strip tags, trim whitespace
     */
    public static function sanitize(string $value): string
    {
        $value = strip_tags($value);
        $value = trim($value);
        return $value;
    }

    /**
     * Sanitize for URLs
     */
    public static function sanitizeUrl(string $url): string
    {
        $url = filter_var($url, FILTER_SANITIZE_URL);
        return rtrim($url, '/');
    }

    /**
     * Sanitize email
     */
    public static function sanitizeEmail(string $email): string
    {
        return filter_var($email, FILTER_SANITIZE_EMAIL);
    }

    /**
     * Validate email format
     */
    public static function validateEmail(string $email): bool
    {
        return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
    }

    /**
     * Validate URL format
     */
    public static function validateUrl(string $url): bool
    {
        return filter_var($url, FILTER_VALIDATE_URL) !== false;
    }

    /**
     * Hash password with bcrypt
     */
    public static function hashPassword(string $password): string
    {
        return password_hash($password, PASSWORD_BCRYPT, ['cost' => HASH_COST]);
    }

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

    /**
     * Check if password needs rehash
     */
    public static function needsRehash(string $hash): bool
    {
        return password_needs_rehash($hash, PASSWORD_BCRYPT, ['cost' => HASH_COST]);
    }

    /**
     * Generate random secure token
     */
    public static function generateToken(int $length = 64): string
    {
        return bin2hex(random_bytes($length));
    }

    /**
     * Generate remember-me token
     */
    public static function generateRememberToken(): string
    {
        return self::generateToken(32);
    }

    /**
     * Simple encryption
     */
    public static function encrypt(string $data, string $key): string
    {
        $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
        $encrypted = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
        return base64_encode($iv . '::' . $encrypted);
    }

    /**
     * Simple decryption
     */
    public static function decrypt(string $data, string $key): string
    {
        $parts = explode('::', base64_decode($data), 2);
        if (count($parts) !== 2) {
            return '';
        }
        [$iv, $encrypted] = $parts;
        return openssl_decrypt($encrypted, 'aes-256-cbc', $key, 0, $iv) ?: '';
    }

    /**
     * Validate file upload
     */
    public static function validateFile(array $file, array $allowedTypes = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'pdf'], int $maxSize = 5242880): array
    {
        $errors = [];
        
        if ($file['error'] !== UPLOAD_ERR_OK) {
            return ['valid' => false, 'errors' => ['File upload failed with error code: ' . $file['error']]];
        }
        
        if ($file['size'] > $maxSize) {
            return ['valid' => false, 'errors' => ['File size exceeds maximum allowed size of ' . ($maxSize / 1048576) . ' MB']];
        }
        
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $allowedTypes)) {
            return ['valid' => false, 'errors' => ['File type "' . $extension . '" is not allowed. Allowed types: ' . implode(', ', $allowedTypes)]];
        }
        
        return ['valid' => true, 'errors' => []];
    }

    /**
     * Detect malicious input
     */
    public static function detectMaliciousInput(array $data): bool
    {
        $patterns = [
            '/(\%27)|(\')|(\-\-)|(\%23)|(#)/i',
            '/(\%24)|(\$)/i',
            '/(\%27)|(\')/i',
            '/((\%3D)|(=))[^\n]*((\%27)|(\')|(\-\-)|(\%3B)|(;))/i',
            '/\w*((\%27)|(\'))\s*((\%6F)|o|(\%4F))((\%72)|r|(\%52))/i',
            '/exec(\s|\+)+(s|x)p\w+/i',
            '/UNION\s+ALL\s+SELECT/i',
            '/\b(ALTER|CREATE|DELETE|DROP|EXEC|INSERT|MERGE|TRUNCATE|UPDATE)\b/i',
        ];
        
        array_walk_recursive($data, function ($value) use ($patterns) {
            if (is_string($value)) {
                foreach ($patterns as $pattern) {
                    if (preg_match($pattern, $value)) {
                        return true;
                    }
                }
            }
        });
        
        return false;
    }
}
