<?php

// Offline CommonMark AST inventory. Does not bootstrap Laravel or fetch links.
declare(strict_types=1);

require $argv[1] ?? dirname(__DIR__, 3).'/vendor/autoload.php';

use League\CommonMark\Environment\Environment;
use League\CommonMark\Extension\CommonMark\CommonMarkCoreExtension;
use League\CommonMark\Extension\CommonMark\Node\Block\BlockQuote;
use League\CommonMark\Extension\CommonMark\Node\Block\Heading;
use League\CommonMark\Extension\CommonMark\Node\Inline\Code;
use League\CommonMark\Extension\CommonMark\Node\Inline\Link;
use League\CommonMark\Node\Block\Paragraph;
use League\CommonMark\Node\Inline\Text;
use League\CommonMark\Node\Node;
use League\CommonMark\Parser\MarkdownParser;

function plainText(Node $node): string
{
    $text = [];
    $walker = $node->walker();
    while ($event = $walker->next()) {
        if ($event->isEntering() && ($event->getNode() instanceof Text || $event->getNode() instanceof Code)) {
            $text[] = $event->getNode()->getLiteral();
        }
    }
    return trim(preg_replace('/\s+/u', ' ', implode(' ', $text)) ?? '');
}

$environment = new Environment(['max_nesting_level' => 100]);
$environment->addExtension(new CommonMarkCoreExtension());
$parser = new MarkdownParser($environment);
$input = json_decode(stream_get_contents(STDIN), true, 512, JSON_THROW_ON_ERROR);
$output = ['parser' => 'league/commonmark', 'version' => Composer\InstalledVersions::getPrettyVersion('league/commonmark'),
    'extensions' => ['CommonMarkCoreExtension'], 'documents' => []];
foreach ($input as $row) {
    $body = base64_decode($row['body_base64'], true);
    if ($body === false) {
        throw new RuntimeException('Invalid body input');
    }
    $document = $parser->parse(preg_replace('/^\xEF\xBB\xBF/', '', $body) ?? $body);
    $result = ['domain' => $row['domain'], 'body_sha256' => hash('sha256', $body),
        'headings' => [], 'links' => [], 'has_blockquote' => false, 'intro_excerpt' => ''];
    $walker = $document->walker();
    while ($event = $walker->next()) {
        if (! $event->isEntering()) {
            continue;
        }
        $node = $event->getNode();
        if ($node instanceof Heading) {
            $result['headings'][] = ['level' => $node->getLevel(), 'text' => plainText($node), 'line' => $node->getStartLine()];
        } elseif ($node instanceof Link) {
            $result['links'][] = ['url' => $node->getUrl(), 'label' => mb_substr(plainText($node), 0, 120)];
        } elseif ($node instanceof BlockQuote) {
            $result['has_blockquote'] = true;
        } elseif ($node instanceof Paragraph && $result['intro_excerpt'] === '') {
            $result['intro_excerpt'] = mb_substr(plainText($node), 0, 180);
        }
    }
    $output['documents'][] = $result;
}
echo json_encode($output, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_THROW_ON_ERROR).PHP_EOL;
