<?php

declare(strict_types=1);

/**
 * SRP Redirect — Pure Functions
 * =============================
 * Stateless validation, sanitization, and transformation functions.
 * No database, file I/O, HTTP calls, or side effects.
 *
 * Extracted from redirect/index.php for:
 *   - Unit testability
 *   - Reuse across modules
 *   - First step toward OOP migration
 */

// ── Token & String Sanitization ──────────────────────────────────────────────

function srp_sanitize_token(string $value, int $max): ?string
{
    $value = trim($value);

    if ($value === '' || strlen($value) > $max) {
        return null;
    }

    return preg_match('/^[A-Za-z0-9_-]+$/', $value) === 1 ? $value : null;
}

function srp_sanitize_title(string $value): string
{
    $value = preg_replace('/[\r\n\t]+/', ' ', trim($value)) ?? '';

    return mb_substr($value, 0, 200, 'UTF-8');
}

// ── URL Validation ───────────────────────────────────────────────────────────

function srp_sanitize_https_url(string $value): ?string
{
    if ($value === '' || strlen($value) > 2048) {
        return null;
    }

    if (filter_var($value, FILTER_VALIDATE_URL) === false) {
        return null;
    }

    $scheme = parse_url($value, PHP_URL_SCHEME);

    return is_string($scheme) && strtolower($scheme) === 'https' ? $value : null;
}

// ── LG (Landing/Direct) Normalization ────────────────────────────────────────

function srp_normalize_lg(mixed $value): string
{
    if (!is_scalar($value)) {
        return 'direct';
    }

    $normalized = strtolower(trim((string) $value));

    if ($normalized === 'landing' || $normalized === '1') {
        return 'landing';
    }

    return 'direct';
}

// ── Device Type Detection ────────────────────────────────────────────────────

/**
 * Build a Mobile Detect instance (mobiledetect.net library) for a given UA.
 */
function srp_mobile_detect(string $userAgent): \Detection\MobileDetect
{
    $detect = new \Detection\MobileDetect();
    $detect->setUserAgent($userAgent);

    return $detect;
}

function srp_device_type(\Detection\MobileDetect $detect): string
{
    // isTablet() first: in this library isMobile() is also true for tablets.
    if ($detect->isTablet()) {
        return 'TABLET';
    }

    if ($detect->isMobile()) {
        return 'WAP';
    }

    return 'WEB';
}

// ── Social Bot Detection ─────────────────────────────────────────────────────

function srp_is_social_bot(string $ua): bool
{
    if ($ua === '') {
        return false;
    }

    // Exclude FB in-app browser (not a crawler)
    if (preg_match('/\b(FBAN|FBAV)\b/', $ua) === 1) {
        return false;
    }

    return preg_match(
        '/facebookexternalhit|facebookcatalog|Facebot|meta-externalagent'
        . '|Twitterbot|WhatsApp|TelegramBot|LinkedInBot|Slackbot|Discordbot|Applebot|Googlebot/i',
        $ua,
    ) === 1;
}

/**
 * Detect a redirect checker / tracker / preview / validator that spoofs a MOBILE
 * device — i.e. a request that claims to be a phone/tablet but carries an
 * automation, HTTP-client, or link-checker/monitor signature. Such requests are
 * served OG meta tags (HTTP 200) like preview bots instead of the real offer
 * redirect, so they only ever see a benign page during the "check redirect" step.
 *
 * Intentionally conservative: BOTH a mobile token AND a probe signature are
 * required. Genuine mobile browsers (Mobile Safari / Chrome Mobile / in-app
 * WebViews) never contain these probe markers, so real mobile visitors are NOT
 * affected. Fully-spoofed UAs that mimic a real browser exactly cannot be caught
 * by UA inspection alone and are out of scope here.
 */
function srp_is_suspicious_mobile_probe(string $ua): bool
{
    if ($ua === '') {
        return false;
    }

    $looksMobile = preg_match(
        '/android|iphone|ipad|ipod|iemobile|windows phone|blackberry|bb10|opera mini|opera mobi|\bmobile\b/i',
        $ua,
    ) === 1;

    if (!$looksMobile) {
        return false;
    }

    return preg_match(
        '/headless|phantomjs|puppeteer|playwright|selenium|webdriver'
        . '|python-requests|python-urllib|aiohttp|httpx|libwww|lwp::|java\/|jakarta'
        . '|okhttp|go-http-client|guzzle|axios|node-fetch|got\/|curl\/|wget|scrapy'
        . '|apache-httpclient|restsharp|postmanruntime|insomnia|httpclient'
        . '|bot|crawler|spider|preview|validator|verif|scanner|monitor|checker|probe|fetcher'
        . '|linkcheck|uptime|pingdom|statuscake|site24x7|datadog|newrelic|ahrefs|semrush/i',
        $ua,
    ) === 1;
}

// ── Country Code Resolution ──────────────────────────────────────────────────

function srp_header_country_code(string $key): ?string
{
    $value = trim(srp_server_string($key));

    if ($value === '' || strlen($value) !== 2 || preg_match('/^[A-Za-z]{2}$/', $value) !== 1) {
        return null;
    }

    $countryCode = strtoupper($value);

    return in_array($countryCode, ['T1', 'XX'], true) ? null : $countryCode;
}

/**
 * @param array<string, mixed> $geo
 */
function srp_geo_country_code(array $geo): string
{
    if (!isset($geo['countryCode']) || !is_string($geo['countryCode']) || $geo['countryCode'] === '') {
        return 'XX';
    }

    return strtoupper($geo['countryCode']);
}

// ── IP Utilities ─────────────────────────────────────────────────────────────

function srp_normalize_ip(string $value): string
{
    $value = trim($value);

    if ($value === '' || strlen($value) > 45) {
        return '';
    }

    return $value;
}

function srp_is_valid_ip(string $ip): bool
{
    return filter_var($ip, FILTER_VALIDATE_IP) !== false;
}

// ── HTTPS Detection ──────────────────────────────────────────────────────────

function srp_is_https(): bool
{
    if (strtolower(srp_server_string('HTTP_X_FORWARDED_PROTO')) === 'https') {
        return true;
    }

    if (str_contains(strtolower(srp_server_string('HTTP_CF_VISITOR')), '"scheme":"https"')) {
        return true;
    }

    if (
        isset($_SERVER['HTTPS'])
        && is_string($_SERVER['HTTPS'])
        && strtolower($_SERVER['HTTPS']) !== 'off'
        && $_SERVER['HTTPS'] !== ''
    ) {
        return true;
    }

    if (
        isset($_SERVER['SERVER_PORT'])
        && is_scalar($_SERVER['SERVER_PORT'])
        && (string) $_SERVER['SERVER_PORT'] === '443'
    ) {
        return true;
    }

    return false;
}

// ── Server Helpers ───────────────────────────────────────────────────────────

function srp_server_string(string $key): string
{
    if (!isset($_SERVER[$key]) || !is_string($_SERVER[$key])) {
        return '';
    }

    return $_SERVER[$key];
}

function srp_validate_host(string $host): bool
{
    return $host !== '' && preg_match('/^[a-zA-Z0-9.\-]+(:\d{1,5})?$/', $host) === 1;
}

// ── Output Escaping ──────────────────────────────────────────────────────────

function srp_e(string $value): string
{
    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
}
