<?php

declare(strict_types=1);

namespace App\Infrastructure\Enrichment\Downloaders;

use MaxMind\Db\Reader;
use Throwable;

/**
 * Cross-provider MMDB sanity check used after every download.
 *
 * MaxMind ships SHA-256 alongside its tarballs; DB-IP and IPinfo do
 * not. For DB-IP and IPinfo the integrity check is gzip-decode (DB-IP
 * only) + open with MaxMind\Db\Reader to read metadata + verify the
 * node count is in a sane range. Truncated or zero-byte downloads
 * fail fast here.
 *
 * Thresholds: country ≥ 100k nodes, ASN ≥ 50k. Empirically the
 * smallest of the three providers (DB-IP Lite ASN ~80k nodes) sits
 * comfortably above; a corrupt download is typically truncated to
 * <1k.
 */
final class MmdbVerifier
{
    public const COUNTRY_MIN_NODES = 100_000;
    public const ASN_MIN_NODES = 50_000;

    public static function assertCountry(string $path): void
    {
        self::assertReadable($path, self::COUNTRY_MIN_NODES);
    }

    public static function assertAsn(string $path): void
    {
        self::assertReadable($path, self::ASN_MIN_NODES);
    }

    private static function assertReadable(string $path, int $minNodes): void
    {
        if (!is_file($path) || filesize($path) === 0) {
            throw new DownloaderException(sprintf('mmdb missing or zero-byte at %s', $path));
        }
        try {
            $reader = new Reader($path);
        } catch (Throwable $e) {
            throw new DownloaderException(
                sprintf('mmdb open failed at %s: %s', $path, $e->getMessage()),
                0,
                $e,
            );
        }
        $metadata = $reader->metadata();
        $nodeCount = $metadata->nodeCount;
        $reader->close();
        if ($nodeCount < $minNodes) {
            throw new DownloaderException(
                sprintf('mmdb node count %d below threshold %d at %s', $nodeCount, $minNodes, $path)
            );
        }
    }
}
