<?php

namespace Limb_Chatbot\Includes\Services;

/**
 * Device info detector
 *
 * Extracts a minimal, normalized set of device + browser + OS categories from the
 * request user-agent. This is intentionally designed to avoid storing raw
 * fingerprinting inputs (e.g. full UA, language header, timezone, screen size).
 *
 * @since 1.0.0
 */
class Device_Info_Detector {

	/**
	 * Collects device information from server variables.
	 *
	 * @return array Device information array.
	 */
	public function collect_device_info(): array {
		$user_agent = sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] ?? '' );

		$browser = $this->detect_browser( $user_agent );
		$os      = $this->detect_os( $user_agent );

		$device_info = array(
			'browser'         => $browser,
			'browser_version' => ( $browser && $browser !== 'Other' ) ? $this->detect_browser_version( $user_agent ) : null,
			'os'              => $os,
			'os_version'      => ( $os && $os !== 'Other' ) ? $this->detect_os_version( $user_agent ) : null,
			'device_type'     => $this->detect_device_type( $user_agent ),
			'platform'        => $this->detect_platform( $user_agent ),
			'is_mobile'       => $this->is_mobile_device( $user_agent ),
			'is_tablet'       => $this->is_tablet_device( $user_agent ),
			'is_desktop'      => ! $this->is_mobile_device( $user_agent ) && ! $this->is_tablet_device( $user_agent ),
		);

		return $device_info;
	}

	/**
	 * Detects browser name from user agent.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string Browser name bucket.
	 */
	private function detect_browser( string $user_agent ): ?string {
		if ( empty( $user_agent ) ) {
			return 'Other';
		}

		// Order matters: check most specific first.
		if ( strpos( $user_agent, 'MSIE' ) !== false || strpos( $user_agent, 'Trident' ) !== false ) {
			return 'Internet Explorer';
		}
		if ( strpos( $user_agent, 'SamsungBrowser/' ) !== false ) {
			return 'Samsung browser';
		}
		if ( strpos( $user_agent, 'UCBrowser/' ) !== false || strpos( $user_agent, 'UC Browser/' ) !== false ) {
			return 'UC Browser';
		}
		if ( strpos( $user_agent, 'YaBrowser/' ) !== false ) {
			return 'Yandex';
		}
		if ( strpos( $user_agent, 'Brave/' ) !== false || strpos( $user_agent, 'Brave Chrome/' ) !== false || strpos( $user_agent, 'Brave Chrome' ) !== false ) {
			return 'Brave';
		}

		// Edge (Chromium-based)
		if ( strpos( $user_agent, 'Edg/' ) !== false || strpos( $user_agent, 'EdgiOS/' ) !== false ) {
			return 'Microsoft Edge';
		}
		// Edge legacy (EdgeHTML)
		if ( strpos( $user_agent, 'Edge/' ) !== false && strpos( $user_agent, 'Edg/' ) === false ) {
			return 'Microsoft Edge';
		}

		// Opera
		if ( strpos( $user_agent, 'OPR/' ) !== false || strpos( $user_agent, 'Opera/' ) !== false ) {
			return 'Opera';
		}

		// Chrome iOS
		if ( strpos( $user_agent, 'CriOS/' ) !== false ) {
			return 'Chrome';
		}
		// Firefox iOS
		if ( strpos( $user_agent, 'FxiOS/' ) !== false ) {
			return 'Firefox';
		}

		// Chrome/Chromium (desktop/Android)
		if ( strpos( $user_agent, 'Chrome/' ) !== false || strpos( $user_agent, 'Chromium/' ) !== false ) {
			// Exclude non-Chrome Chromium-based browsers already handled above.
			if ( strpos( $user_agent, 'Edg/' ) === false && strpos( $user_agent, 'OPR/' ) === false && strpos( $user_agent, 'SamsungBrowser/' ) === false ) {
				return 'Chrome';
			}
		}

		// Firefox
		if ( strpos( $user_agent, 'Firefox/' ) !== false ) {
			return 'Firefox';
		}

		// Safari (must be checked after Chrome/Edge/etc since they contain "Safari")
		if ( strpos( $user_agent, 'Safari/' ) !== false && strpos( $user_agent, 'Chrome/' ) === false && strpos( $user_agent, 'CriOS/' ) === false && strpos( $user_agent, 'Edg/' ) === false && strpos( $user_agent, 'EdgiOS/' ) === false && strpos( $user_agent, 'OPR/' ) === false ) {
			return 'Safari';
		}

		return 'Other';
	}

	/**
	 * Detects browser version from user agent.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string|null Browser version.
	 */
	private function detect_browser_version( string $user_agent ): ?string {
		if ( empty( $user_agent ) ) {
			return null;
		}

		// Order matters: prefer the version token for the actual browser brand.
		if ( preg_match( '/MSIE\s([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		if ( preg_match( '/rv:([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		if ( preg_match( '/SamsungBrowser\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		if ( preg_match( '/(?:UCBrowser|UC Browser)\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		if ( preg_match( '/YaBrowser\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		if ( preg_match( '/Brave\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		// Edge
		if ( preg_match( '/Edg\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		if ( preg_match( '/EdgiOS\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		// Edge legacy
		if ( preg_match( '/Edge\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		// Opera
		if ( preg_match( '/OPR\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		if ( preg_match( '/Opera\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		// iOS Chrome/Firefox
		if ( preg_match( '/CriOS\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		if ( preg_match( '/FxiOS\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		// Chrome
		if ( preg_match( '/Chrome\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		// Firefox
		if ( preg_match( '/Firefox\/([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		// Safari
		if ( preg_match( '/Version\/([\d.]+).*Safari/', $user_agent, $matches ) ) {
			return $matches[1];
		}

		return null;
	}

	/**
	 * Detects operating system from user agent.
	 *
	 * Allowed buckets:
	 * windows, macos, linux, ios, android, other.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string OS name bucket.
	 */
	private function detect_os( string $user_agent ): ?string {
		if ( empty( $user_agent ) ) {
			return 'Other';
		}

		// iOS (iPhone/iPad/iPod)
		if ( strpos( $user_agent, 'iOS' ) !== false || strpos( $user_agent, 'iPhone' ) !== false || strpos( $user_agent, 'iPad' ) !== false || strpos( $user_agent, 'iPod' ) !== false ) {
			return 'iOS';
		}

		// Android
		if ( strpos( $user_agent, 'Android' ) !== false ) {
			return 'Android';
		}

		// macOS
		if ( strpos( $user_agent, 'Mac OS X' ) !== false || strpos( $user_agent, 'Macintosh' ) !== false ) {
			return 'macOS';
		}

		// Chrome OS / other Linux variants should fall into "Other".
		if ( strpos( $user_agent, 'CrOS' ) !== false ) {
			return 'Other';
		}

		// Windows (avoid Windows Phone classifying as Windows).
		if ( strpos( $user_agent, 'Windows' ) !== false && strpos( $user_agent, 'Windows Phone' ) === false ) {
			return 'Windows';
		}

		// Linux (excluding Chrome OS handled above).
		if ( strpos( $user_agent, 'Linux' ) !== false ) {
			return 'Linux';
		}

		// Everything else
		if ( strpos( $user_agent, 'Windows Phone' ) !== false ) {
			return 'Other';
		}

		if ( strpos( $user_agent, 'Unknown' ) !== false ) {
			return 'Other';
		}

		return 'Other';
	}

	/**
	 * Detects operating system version from user agent.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string|null OS version.
	 */
	private function detect_os_version( string $user_agent ): ?string {
		if ( empty( $user_agent ) ) {
			return null;
		}

		// Windows version
		if ( preg_match( '/Windows NT ([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		// macOS version
		if ( preg_match( '/Mac OS X ([\d_]+)/', $user_agent, $matches ) ) {
			return str_replace( '_', '.', $matches[1] );
		}
		// Android version
		if ( preg_match( '/Android ([\d.]+)/', $user_agent, $matches ) ) {
			return $matches[1];
		}
		// iOS version
		if ( preg_match( '/OS ([\d_]+)/', $user_agent, $matches ) ) {
			return str_replace( '_', '.', $matches[1] );
		}

		return null;
	}

	/**
	 * Detects device type from user agent.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string Device type (mobile, tablet, desktop).
	 */
	private function detect_device_type( string $user_agent ): string {
		if ( $this->is_mobile_device( $user_agent ) ) {
			return 'mobile';
		} elseif ( $this->is_tablet_device( $user_agent ) ) {
			return 'tablet';
		}

		return 'desktop';
	}

	/**
	 * Checks if device is mobile.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return bool True if mobile device.
	 */
	private function is_mobile_device( string $user_agent ): bool {
		if ( empty( $user_agent ) ) {
			return false;
		}

		return (bool) preg_match( '/Mobile|Android|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i', $user_agent );
	}

	/**
	 * Checks if device is tablet.
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return bool True if tablet device.
	 */
	private function is_tablet_device( string $user_agent ): bool {
		if ( empty( $user_agent ) ) {
			return false;
		}

		return (bool) preg_match( '/iPad|Android(?!.*Mobile)|Tablet/i', $user_agent );
	}

	/**
	 * Detects platform (mobile/desktop).
	 *
	 * @param  string  $user_agent  User agent string.
	 *
	 * @return string Platform type.
	 */
	private function detect_platform( string $user_agent ): string {
		if ( $this->is_mobile_device( $user_agent ) || $this->is_tablet_device( $user_agent ) ) {
			return 'mobile';
		}

		return 'desktop';
	}
}

