<?php

declare(strict_types=1);

function usage(): void
{
    $script = basename(__FILE__);

    fwrite(STDERR, <<<TXT
Usage:
  php scripts/{$script} --base=https://skinbase.org /@gregor /categories /wallpapers
  php scripts/{$script} https://skinbase.org/@gregor https://skinbase.org/categories

Classifications:
  INERTIA_SSR     id="app" + data-page + non-empty app HTML
  INERTIA_NO_SSR  id="app" + data-page + empty app HTML
  NOT_INERTIA     missing id="app" or missing data-page

TXT);
}

function isAbsoluteUrl(string $value): bool
{
    return (bool) preg_match('~^https?://~i', $value);
}

function joinUrl(string $baseUrl, string $path): string
{
    return rtrim($baseUrl, '/') . '/' . ltrim($path, '/');
}

function resolveTargets(array $arguments): array
{
    $baseUrl = null;
    $targets = [];

    foreach ($arguments as $argument) {
        if (str_starts_with($argument, '--base=')) {
            $baseUrl = substr($argument, 7);
            continue;
        }

        if ($argument === '--help' || $argument === '-h') {
            usage();
            exit(0);
        }

        $targets[] = $argument;
    }

    if ($targets === []) {
        usage();
        exit(1);
    }

    return array_map(static function (string $target) use ($baseUrl): string {
        if (isAbsoluteUrl($target)) {
            return $target;
        }

        if ($baseUrl === null || $baseUrl === '') {
            fwrite(STDERR, "Relative path '{$target}' requires --base=...\n");
            exit(1);
        }

        return joinUrl($baseUrl, $target);
    }, $targets);
}

function fetchUrl(string $url): array
{
    if (function_exists('curl_init')) {
        $handle = curl_init($url);
        curl_setopt_array($handle, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_MAXREDIRS => 5,
            CURLOPT_TIMEOUT => 20,
            CURLOPT_CONNECTTIMEOUT => 10,
            CURLOPT_USERAGENT => 'Skinbase Inertia Checker/1.0',
            CURLOPT_HEADER => true,
        ]);

        $raw = curl_exec($handle);
        if ($raw === false) {
            $error = curl_error($handle);
            curl_close($handle);

            throw new RuntimeException($error !== '' ? $error : 'Unknown cURL error');
        }

        $status = (int) curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
        $headerSize = (int) curl_getinfo($handle, CURLINFO_HEADER_SIZE);
        curl_close($handle);

        return [
            'status' => $status,
            'body' => substr($raw, $headerSize),
        ];
    }

    $context = stream_context_create([
        'http' => [
            'method' => 'GET',
            'follow_location' => 1,
            'max_redirects' => 5,
            'timeout' => 20,
            'header' => "User-Agent: Skinbase Inertia Checker/1.0\r\n",
            'ignore_errors' => true,
        ],
    ]);

    $body = @file_get_contents($url, false, $context);
    if ($body === false) {
        $error = error_get_last();
        throw new RuntimeException($error['message'] ?? 'HTTP request failed');
    }

    $headers = $http_response_header ?? [];
    $status = 0;

    foreach ($headers as $header) {
        if (preg_match('~^HTTP/\S+\s+(\d{3})~', $header, $matches)) {
            $status = (int) $matches[1];
        }
    }

    return [
        'status' => $status,
        'body' => $body,
    ];
}

function classifyHtml(string $html): string
{
    $hasApp = str_contains($html, 'id="app"');
    $hasDataPage = str_contains($html, 'data-page="');

    if (! $hasApp || ! $hasDataPage) {
        return 'NOT_INERTIA';
    }

    if (! preg_match('~<div id="app"[^>]*>(.*?)</div>~si', $html, $matches)) {
        return 'INERTIA_UNKNOWN';
    }

    return trim($matches[1]) === '' ? 'INERTIA_NO_SSR' : 'INERTIA_SSR';
}

$targets = resolveTargets(array_slice($argv, 1));

foreach ($targets as $url) {
    try {
        $response = fetchUrl($url);
        $classification = classifyHtml($response['body']);
        printf("%d\t%s\t%s\n", $response['status'], $classification, $url);
    } catch (Throwable $exception) {
        printf("ERROR\t%s\t%s\n", $exception->getMessage(), $url);
    }
}