<?php

declare(strict_types=1);

namespace App\Framework\Waf\BotProtection\ValueObjects;

use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Device profile with hardware and software characteristics
 */
final readonly class DeviceProfile
{
    public function __construct(
        public string $deviceId,
        public array $characteristics,
        public array $suspiciousFeatures,
        public float $suspicionScore,
        public Timestamp $createdAt,
        public ?string $operatingSystem = null,
        public ?string $browser = null,
        public ?string $deviceType = null,
        public ?array $hardwareSpecs = null,
        public ?array $networkInfo = null,
        public ?array $locationData = null,
        public ?float $batteryLevel = null,
        public ?int $memorySize = null,
        public ?int $cpuCores = null,
        public ?string $gpuRenderer = null,
        public ?array $connectionType = null,
        public bool $isVirtualMachine = false,
        public bool $isHeadless = false,
        public bool $hasWebDriver = false
    ) {
    }

    /**
     * Create from device data
     */
    public static function fromData(array $data, Timestamp $timestamp): self
    {
        $characteristics = self::extractCharacteristics($data);
        $suspiciousFeatures = self::detectSuspiciousFeatures($characteristics);
        $suspicionScore = self::calculateSuspicionScore($suspiciousFeatures, $characteristics);

        return new self(
            deviceId: self::generateDeviceId($characteristics),
            characteristics: $characteristics,
            suspiciousFeatures: $suspiciousFeatures,
            suspicionScore: $suspicionScore,
            createdAt: $timestamp,
            operatingSystem: $data['os'] ?? null,
            browser: $data['browser'] ?? null,
            deviceType: $data['device_type'] ?? null,
            hardwareSpecs: $data['hardware'] ?? null,
            networkInfo: $data['network'] ?? null,
            locationData: $data['location'] ?? null,
            batteryLevel: $data['battery_level'] ?? null,
            memorySize: $data['memory_size'] ?? null,
            cpuCores: $data['cpu_cores'] ?? null,
            gpuRenderer: $data['gpu_renderer'] ?? null,
            connectionType: $data['connection_type'] ?? null,
            isVirtualMachine: $data['is_vm'] ?? false,
            isHeadless: $data['is_headless'] ?? false,
            hasWebDriver: $data['has_webdriver'] ?? false
        );
    }

    /**
     * Check if device is suspicious
     */
    public function isSuspicious(): bool
    {
        return $this->suspicionScore > 60.0;
    }

    /**
     * Check if device is highly suspicious
     */
    public function isHighlySuspicious(): bool
    {
        return $this->suspicionScore > 85.0;
    }

    /**
     * Get suspicion score
     */
    public function getSuspicionScore(): float
    {
        return $this->suspicionScore;
    }

    /**
     * Get suspicious features
     */
    public function getSuspiciousFeatures(): array
    {
        return $this->suspiciousFeatures;
    }

    /**
     * Check if device is likely a bot
     */
    public function isLikelyBot(): bool
    {
        return $this->isVirtualMachine || $this->isHeadless || $this->hasWebDriver || $this->suspicionScore > 90.0;
    }

    /**
     * Check if device matches another profile
     */
    public function matches(self $other): bool
    {
        return $this->deviceId === $other->deviceId;
    }

    /**
     * Calculate similarity with another device profile
     */
    public function similarity(self $other): float
    {
        $commonCharacteristics = array_intersect_key($this->characteristics, $other->characteristics);
        $totalCharacteristics = array_merge($this->characteristics, $other->characteristics);

        if (empty($totalCharacteristics)) {
            return 0.0;
        }

        $matchingCharacteristics = 0;
        foreach ($commonCharacteristics as $key => $value) {
            if ($this->characteristics[$key] === $other->characteristics[$key]) {
                $matchingCharacteristics++;
            }
        }

        return ($matchingCharacteristics / count($totalCharacteristics)) * 100;
    }

    /**
     * Extract device characteristics
     */
    private static function extractCharacteristics(array $data): array
    {
        return [
            'os_hash' => hash('sha256', $data['os'] ?? ''),
            'browser_hash' => hash('sha256', $data['browser'] ?? ''),
            'device_type' => $data['device_type'] ?? 'unknown',
            'memory_size' => $data['memory_size'] ?? null,
            'cpu_cores' => $data['cpu_cores'] ?? null,
            'gpu_hash' => isset($data['gpu_renderer']) ? hash('sha256', $data['gpu_renderer']) : null,
            'screen_width' => $data['hardware']['screen_width'] ?? null,
            'screen_height' => $data['hardware']['screen_height'] ?? null,
            'timezone_offset' => $data['location']['timezone_offset'] ?? null,
            'language' => $data['language'] ?? null,
            'connection_type' => $data['connection_type']['type'] ?? null,
            'is_vm' => $data['is_vm'] ?? false,
            'is_headless' => $data['is_headless'] ?? false,
            'has_webdriver' => $data['has_webdriver'] ?? false,
            'battery_available' => isset($data['battery_level']),
        ];
    }

    /**
     * Detect suspicious device features
     */
    private static function detectSuspiciousFeatures(array $characteristics): array
    {
        $suspicious = [];

        // Check for virtualization indicators
        if ($characteristics['is_vm']) {
            $suspicious['virtual_machine'] = 'Device is running in a virtual machine';
        }

        if ($characteristics['is_headless']) {
            $suspicious['headless_browser'] = 'Headless browser detected';
        }

        if ($characteristics['has_webdriver']) {
            $suspicious['webdriver_detected'] = 'WebDriver automation detected';
        }

        // Check for unusual hardware specifications
        if (isset($characteristics['memory_size']) && $characteristics['memory_size'] < 1024) {
            $suspicious['low_memory'] = "Unusually low memory: {$characteristics['memory_size']}MB";
        }

        if (isset($characteristics['cpu_cores']) && $characteristics['cpu_cores'] > 64) {
            $suspicious['high_cpu_cores'] = "Unusually high CPU cores: {$characteristics['cpu_cores']}";
        }

        // Check for missing expected features
        if (! $characteristics['battery_available'] && $characteristics['device_type'] === 'mobile') {
            $suspicious['missing_battery'] = 'Mobile device without battery information';
        }

        // Check for inconsistent characteristics
        if ($characteristics['device_type'] === 'mobile' &&
            isset($characteristics['screen_width']) &&
            $characteristics['screen_width'] > 1920) {
            $suspicious['inconsistent_mobile'] = 'Mobile device with desktop-like screen resolution';
        }

        return $suspicious;
    }

    /**
     * Calculate suspicion score
     */
    private static function calculateSuspicionScore(array $suspiciousFeatures, array $characteristics): float
    {
        $score = 0.0;

        // Weight suspicious features
        $weights = [
            'virtual_machine' => 40,
            'headless_browser' => 50,
            'webdriver_detected' => 60,
            'low_memory' => 20,
            'high_cpu_cores' => 25,
            'missing_battery' => 15,
            'inconsistent_mobile' => 30,
        ];

        foreach ($suspiciousFeatures as $feature => $description) {
            $score += $weights[$feature] ?? 10;
        }

        // Additional scoring based on characteristic patterns
        if ($characteristics['is_vm'] && $characteristics['is_headless'] && $characteristics['has_webdriver']) {
            $score += 30; // Triple threat bonus
        }

        return min(100.0, $score);
    }

    /**
     * Generate unique device ID
     */
    private static function generateDeviceId(array $characteristics): string
    {
        $identifiers = [
            $characteristics['os_hash'] ?? '',
            $characteristics['browser_hash'] ?? '',
            $characteristics['gpu_hash'] ?? '',
            $characteristics['screen_width'] ?? '',
            $characteristics['screen_height'] ?? '',
            $characteristics['memory_size'] ?? '',
            $characteristics['cpu_cores'] ?? '',
        ];

        return hash('sha256', implode('|', $identifiers));
    }

    /**
     * Convert to array
     */
    public function toArray(): array
    {
        return [
            'device_id' => $this->deviceId,
            'suspicion_score' => $this->suspicionScore,
            'is_suspicious' => $this->isSuspicious(),
            'is_highly_suspicious' => $this->isHighlySuspicious(),
            'is_likely_bot' => $this->isLikelyBot(),
            'suspicious_features' => $this->suspiciousFeatures,
            'created_at' => $this->createdAt->toIsoString(),
            'operating_system' => $this->operatingSystem,
            'browser' => $this->browser,
            'device_type' => $this->deviceType,
            'hardware_specs' => $this->hardwareSpecs,
            'network_info' => $this->networkInfo,
            'location_data' => $this->locationData,
            'battery_level' => $this->batteryLevel,
            'memory_size' => $this->memorySize,
            'cpu_cores' => $this->cpuCores,
            'gpu_renderer' => $this->gpuRenderer,
            'connection_type' => $this->connectionType,
            'is_virtual_machine' => $this->isVirtualMachine,
            'is_headless' => $this->isHeadless,
            'has_webdriver' => $this->hasWebDriver,
        ];
    }
}
