<?php

declare(strict_types=1);

namespace App\Administration\Domain\Model\Session;

/**
 * Informations sur l'appareil/navigateur de la session.
 *
 * Parse le User-Agent pour extraire des informations lisibles :
 * - device : Desktop, Mobile, Tablet
 * - browser : Chrome 120, Firefox 121, Safari 17...
 * - os : Windows 10, macOS 10.15, iOS 17.2, Android 14...
 *
 * Le rawUserAgent est conservé pour le fingerprinting.
 *
 * @see Story 1.6 - Gestion des sessions
 */
final readonly class DeviceInfo
{
    private function __construct(
        public string $device,
        public string $browser,
        public string $os,
        public string $rawUserAgent,
    ) {
    }

    /**
     * Parse un User-Agent pour extraire les informations de l'appareil.
     */
    public static function fromUserAgent(string $userAgent): self
    {
        if ($userAgent === '') {
            return new self(
                device: 'Inconnu',
                browser: 'Inconnu',
                os: 'Inconnu',
                rawUserAgent: '',
            );
        }

        $device = self::parseDevice($userAgent);
        $browser = self::parseBrowser($userAgent);
        $os = self::parseOs($userAgent);

        return new self(
            device: $device,
            browser: $browser,
            os: $os,
            rawUserAgent: $userAgent,
        );
    }

    /**
     * Reconstitue les informations depuis le stockage.
     *
     * @internal Pour usage Infrastructure uniquement
     */
    public static function reconstitute(
        string $device,
        string $browser,
        string $os,
        string $rawUserAgent,
    ): self {
        return new self($device, $browser, $os, $rawUserAgent);
    }

    /**
     * Indique si l'appareil est mobile (phone ou tablet).
     */
    public function isMobile(): bool
    {
        return $this->device === 'Mobile' || $this->device === 'Tablet';
    }

    private static function parseDevice(string $userAgent): string
    {
        $ua = strtolower($userAgent);

        if (str_contains($ua, 'ipad')) {
            return 'Tablet';
        }

        if (str_contains($ua, 'mobile') || str_contains($ua, 'iphone') || str_contains($ua, 'android')) {
            if (str_contains($ua, 'tablet')) {
                return 'Tablet';
            }

            return 'Mobile';
        }

        if (str_contains($ua, 'windows') || str_contains($ua, 'macintosh') || str_contains($ua, 'linux')) {
            return 'Desktop';
        }

        return 'Inconnu';
    }

    private static function parseBrowser(string $userAgent): string
    {
        // Edge doit être testé avant Chrome car Edge contient "Chrome"
        if (preg_match('/Edg(?:e|A|iOS)?\/(\d+)/', $userAgent, $matches)) {
            return "Edge {$matches[1]}";
        }

        if (preg_match('/Chrome\/(\d+)/', $userAgent, $matches)) {
            return "Chrome {$matches[1]}";
        }

        if (preg_match('/Firefox\/(\d+)/', $userAgent, $matches)) {
            return "Firefox {$matches[1]}";
        }

        // Safari: chercher Version/ pour la version affichée
        if (preg_match('/Version\/(\d+)/', $userAgent, $matches) && str_contains($userAgent, 'Safari')) {
            return "Safari {$matches[1]}";
        }

        return 'Inconnu';
    }

    private static function parseOs(string $userAgent): string
    {
        // Windows
        if (preg_match('/Windows NT (\d+\.\d+)/', $userAgent, $matches)) {
            $version = match ($matches[1]) {
                '10.0' => '10',
                '6.3' => '8.1',
                '6.2' => '8',
                '6.1' => '7',
                default => $matches[1],
            };

            return "Windows {$version}";
        }

        // macOS
        if (preg_match('/Mac OS X (\d+[._]\d+)/', $userAgent, $matches)) {
            $version = str_replace('_', '.', $matches[1]);

            return "macOS {$version}";
        }

        // iPadOS
        if (preg_match('/iPad.*OS (\d+[._]\d+)/', $userAgent, $matches)) {
            $version = str_replace('_', '.', $matches[1]);

            return "iPadOS {$version}";
        }

        // iOS
        if (preg_match('/iPhone.*OS (\d+[._]\d+)/', $userAgent, $matches)) {
            $version = str_replace('_', '.', $matches[1]);

            return "iOS {$version}";
        }

        // Android
        if (preg_match('/Android (\d+)/', $userAgent, $matches)) {
            return "Android {$matches[1]}";
        }

        // Linux (générique)
        if (str_contains($userAgent, 'Linux')) {
            return 'Linux';
        }

        return 'Inconnu';
    }
}
