<?php

namespace App\Support;

use InvalidArgumentException;

class OutboundUrl
{
    /**
     * Reject provider URLs that can reach this server, private networks, or
     * cloud metadata. DNS validation is skipped only in automated tests where
     * HTTP is faked and fixture hostnames deliberately do not resolve.
     */
    public static function assertPublicHttp(string $url): void
    {
        $parts = parse_url($url);
        $scheme = strtolower((string) ($parts['scheme'] ?? ''));
        $host = strtolower(rtrim((string) ($parts['host'] ?? ''), '.'));

        if (!in_array($scheme, ['http', 'https'], true) || $host === '') {
            throw new InvalidArgumentException('Provider feed URL must use HTTP or HTTPS.');
        }

        if (!mb_check_encoding($host, 'ASCII')
            || in_array($host, ['localhost', 'metadata', 'metadata.google.internal'], true)
            || str_ends_with($host, '.localhost')
            || str_ends_with($host, '.local')
            || str_ends_with($host, '.internal')) {
            throw new InvalidArgumentException('Provider feed URL cannot target a local or internal host.');
        }

        if (filter_var($host, FILTER_VALIDATE_IP)) {
            self::assertPublicIp($host);
            return;
        }

        if (app()->environment('testing')) {
            return;
        }

        $records = @dns_get_record($host, DNS_A | DNS_AAAA);
        $ips = collect(is_array($records) ? $records : [])
            ->map(fn ($record) => $record['ip'] ?? $record['ipv6'] ?? null)
            ->filter()
            ->unique();

        if ($ips->isEmpty()) {
            throw new InvalidArgumentException('Provider feed host could not be resolved.');
        }

        $ips->each(fn ($ip) => self::assertPublicIp((string) $ip));
    }

    private static function assertPublicIp(string $ip): void
    {
        $flags = FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;

        if (!filter_var($ip, FILTER_VALIDATE_IP, $flags) || $ip === '169.254.169.254') {
            throw new InvalidArgumentException('Provider feed URL resolved to a private or reserved address.');
        }
    }
}
