<?php

namespace App\Helpers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\RateLimiter;

class SecurityHelper
{
    /**
     * Common weak passwords to check against
     */
    protected static $commonPasswords = [
        'password', '123456', '123456789', 'qwerty', 'abc123', 'password123',
        'admin', 'letmein', 'welcome', 'monkey', '1234567890', 'dragon',
        'master', 'shadow', 'superman', 'michael', 'football', 'baseball',
        'liverpool', 'jordan', 'harley', 'robert', 'matthew', 'daniel',
        'andrew', 'joshua', 'anthony', 'william', 'david', 'charles',
        'thomas', 'christopher', 'joseph', 'jessica', 'ashley', 'amanda',
        'melissa', 'sarah', 'michelle', 'kimberly', 'amy', 'angela',
        'jennifer', 'elizabeth', 'lisa', 'stephanie', 'nicole', 'rebecca',
        'sharon', 'cynthia', 'kathleen', 'helen', 'deborah', 'rachel',
        'carolyn', 'janet', 'virginia', 'maria', 'heather', 'diane',
        'julie', 'joyce', 'victoria', 'kelly', 'christina', 'joan',
        'evelyn', 'lauren', 'judith', 'megan', 'cheryl', 'andrea',
        'hannah', 'jacqueline', 'martha', 'gloria', 'teresa', 'sara',
        'janice', 'marie', 'julia', 'kathryn', 'frances', 'jean',
        'abigail', 'alice', 'judy', 'ruth', 'anna', 'denise', 'marilyn',
        'beverly', 'charlotte', 'marie', 'diana', 'helen', 'julie'
    ];

    /**
     * Validate password strength
     */
    public static function validatePasswordStrength(string $password, array $userData = []): array
    {
        $errors = [];
        $config = config('security.password_policy');

        // Check minimum length
        if (strlen($password) < $config['min_length']) {
            $errors[] = "رمز عبور باید حداقل {$config['min_length']} کاراکتر باشد.";
        }

        // Check maximum length
        if (strlen($password) > $config['max_length']) {
            $errors[] = "رمز عبور نباید بیش از {$config['max_length']} کاراکتر باشد.";
        }

        // Check for uppercase letters
        if ($config['require_uppercase'] && !preg_match('/[A-Z]/', $password)) {
            $errors[] = 'رمز عبور باید شامل حداقل یک حرف بزرگ انگلیسی باشد.';
        }

        // Check for lowercase letters
        if ($config['require_lowercase'] && !preg_match('/[a-z]/', $password)) {
            $errors[] = 'رمز عبور باید شامل حداقل یک حرف کوچک انگلیسی باشد.';
        }

        // Check for numbers
        if ($config['require_numbers'] && !preg_match('/[0-9]/', $password)) {
            $errors[] = 'رمز عبور باید شامل حداقل یک عدد باشد.';
        }

        // Check for special characters
        if ($config['require_special_chars'] && !preg_match('/[^a-zA-Z0-9]/', $password)) {
            $errors[] = 'رمز عبور باید شامل حداقل یک کاراکتر خاص باشد.';
        }

        // Check against common passwords
        if ($config['prevent_common_passwords'] && in_array(strtolower($password), self::$commonPasswords)) {
            $errors[] = 'این رمز عبور بسیار رایج است. لطفاً رمز عبور قوی‌تری انتخاب کنید.';
        }

        // Check against personal information
        if ($config['prevent_personal_info'] && !empty($userData)) {
            foreach ($userData as $info) {
                if (!empty($info) && strlen($info) > 2 && stripos($password, $info) !== false) {
                    $errors[] = 'رمز عبور نباید شامل اطلاعات شخصی شما باشد.';
                    break;
                }
            }
        }

        return $errors;
    }

    /**
     * Generate secure random password
     */
    public static function generateSecurePassword(int $length = 12): string
    {
        $uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $lowercase = 'abcdefghijklmnopqrstuvwxyz';
        $numbers = '0123456789';
        $special = '!@#$%^&*()_+-=[]{}|;:,.<>?';

        $password = '';
        $password .= $uppercase[random_int(0, strlen($uppercase) - 1)];
        $password .= $lowercase[random_int(0, strlen($lowercase) - 1)];
        $password .= $numbers[random_int(0, strlen($numbers) - 1)];
        $password .= $special[random_int(0, strlen($special) - 1)];

        $allChars = $uppercase . $lowercase . $numbers . $special;
        for ($i = 4; $i < $length; $i++) {
            $password .= $allChars[random_int(0, strlen($allChars) - 1)];
        }

        return str_shuffle($password);
    }

    /**
     * Check if IP is suspicious
     */
    public static function isSuspiciousIP(string $ip): bool
    {
        // Check against known malicious IP ranges
        $suspiciousRanges = [
            '10.0.0.0/8',
            '172.16.0.0/12',
            '192.168.0.0/16',
            '127.0.0.0/8',
            '169.254.0.0/16',
            '224.0.0.0/4',
            '240.0.0.0/4'
        ];

        foreach ($suspiciousRanges as $range) {
            if (self::ipInRange($ip, $range)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Check if IP is in range
     */
    public static function ipInRange(string $ip, string $range): bool
    {
        if (strpos($range, '/') === false) {
            return $ip === $range;
        }

        list($subnet, $bits) = explode('/', $range);
        $ip = ip2long($ip);
        $subnet = ip2long($subnet);
        $mask = -1 << (32 - $bits);
        $subnet &= $mask;

        return ($ip & $mask) === $subnet;
    }

    /**
     * Sanitize input data
     */
    public static function sanitizeInput(string $input): string
    {
        // Remove null bytes
        $input = str_replace("\0", '', $input);

        // Remove control characters
        $input = preg_replace('/[\x00-\x1F\x7F]/', '', $input);

        // Trim whitespace
        $input = trim($input);

        // Convert HTML entities
        $input = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');

        return $input;
    }

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

    /**
     * Hash sensitive data
     */
    public static function hashSensitiveData(string $data): string
    {
        return Hash::make($data);
    }

    /**
     * Verify hashed data
     */
    public static function verifySensitiveData(string $data, string $hash): bool
    {
        return Hash::check($data, $hash);
    }

    /**
     * Log security event
     */
    public static function logSecurityEvent(string $event, array $data = []): void
    {
        if (config('security.logging.log_security_events')) {
            Log::channel('security')->warning($event, array_merge($data, [
                'timestamp' => now()->toISOString(),
                'ip' => request()->ip(),
                'user_agent' => request()->userAgent(),
            ]));
        }
    }

    /**
     * Check rate limit
     */
    public static function checkRateLimit(string $key, int $maxAttempts, int $decayMinutes = 1): bool
    {
        return RateLimiter::tooManyAttempts($key, $maxAttempts);
    }

    /**
     * Hit rate limiter
     */
    public static function hitRateLimit(string $key, int $decaySeconds = 60): void
    {
        RateLimiter::hit($key, $decaySeconds);
    }

    /**
     * Clear rate limiter
     */
    public static function clearRateLimit(string $key): void
    {
        RateLimiter::clear($key);
    }

    /**
     * Get remaining rate limit attempts
     */
    public static function remainingAttempts(string $key, int $maxAttempts): int
    {
        return RateLimiter::remaining($key, $maxAttempts);
    }

    /**
     * Get available rate limit attempts in seconds
     */
    public static function availableIn(string $key): int
    {
        return RateLimiter::availableIn($key);
    }

    /**
     * Validate CSRF token manually
     */
    public static function validateCsrfToken(Request $request): bool
    {
        $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
        
        if (!$token && $header = $request->header('X-XSRF-TOKEN')) {
            try {
                $token = decrypt($header, false);
            } catch (\Exception $e) {
                return false;
            }
        }

        return $token && hash_equals($request->session()->token(), $token);
    }

    /**
     * Check if request is from trusted source
     */
    public static function isTrustedSource(Request $request): bool
    {
        $trustedIPs = config('security.ip_filtering.whitelist', '');
        if (empty($trustedIPs)) {
            return false;
        }

        $trustedIPs = explode(',', $trustedIPs);
        $clientIP = $request->ip();

        foreach ($trustedIPs as $trustedIP) {
            $trustedIP = trim($trustedIP);
            if (strpos($trustedIP, '/') !== false) {
                if (self::ipInRange($clientIP, $trustedIP)) {
                    return true;
                }
            } elseif ($clientIP === $trustedIP) {
                return true;
            }
        }

        return false;
    }

    /**
     * Encrypt sensitive data
     */
    public static function encryptSensitiveData(string $data): string
    {
        return encrypt($data);
    }

    /**
     * Decrypt sensitive data
     */
    public static function decryptSensitiveData(string $encryptedData): string
    {
        try {
            return decrypt($encryptedData);
        } catch (\Exception $e) {
            throw new \InvalidArgumentException('Unable to decrypt data');
        }
    }
}
