<?php

namespace App\Crawlers;

use GuzzleHttp\Exception\RequestException;
use Illuminate\Support\Facades\Cache;
use Mtc\MercuryDataModels\ContentMigrationEntry;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
use Spatie\Crawler\CrawlObservers\CrawlObserver;

class ContentMigrationCrawlObserver extends CrawlObserver
{
    private array $seenUrls;

    private int $crawledCount = 0;

    private int $importedCount = 0;

    public function __construct(private string $cacheKey)
    {
        $this->seenUrls = array_flip(
            ContentMigrationEntry::pluck('original_url')
                ->map(fn ($url) => $this->normaliseUrl($url))
                ->toArray()
        );
    }

    public function crawled(
        UriInterface $url,
        ResponseInterface $response,
        ?UriInterface $foundOnUrl = null,
        ?string $linkText = null,
    ): void {
        $contentType = $response->getHeaderLine('Content-Type');
        if (!str_contains($contentType, 'text/html')) {
            return;
        }

        $this->crawledCount++;

        $normalised = $this->normaliseUrl((string) $url);

        if (isset($this->seenUrls[$normalised])) {
            $this->updateProgress();

            return;
        }

        ContentMigrationEntry::create(['original_url' => $normalised]);
        $this->seenUrls[$normalised] = true;
        $this->importedCount++;

        $this->updateProgress();
    }

    public function crawlFailed(
        UriInterface $url,
        RequestException $requestException,
        ?UriInterface $foundOnUrl = null,
        ?string $linkText = null,
    ): void {
        $this->crawledCount++;
        $this->updateProgress();
    }

    public function finishedCrawling(): void
    {
        Cache::put($this->cacheKey, [
            'status' => 'complete',
            'crawled' => $this->crawledCount,
            'imported' => $this->importedCount,
        ], now()->addMinutes(30));
    }

    private function normaliseUrl(string $url): string
    {
        $parsed = parse_url($url);

        $scheme = $parsed['scheme'] ?? 'https';
        $host = $parsed['host'] ?? '';
        $path = rtrim($parsed['path'] ?? '', '/');

        return strtolower($scheme . '://' . $host) . $path;
    }

    private function updateProgress(): void
    {
        if ($this->crawledCount % 10 !== 0) {
            return;
        }

        Cache::put($this->cacheKey, [
            'status' => 'crawling',
            'crawled' => $this->crawledCount,
            'imported' => $this->importedCount,
        ], now()->addMinutes(30));
    }
}
