<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Support;

if (! defined('ABSPATH')) {
    exit;
}

final class RemoteUrlGuard
{
    public static function normalize(string $url): string
    {
        $url = trim($url);
        if ($url === '') {
            return '';
        }

        if (function_exists('esc_url_raw')) {
            $url = esc_url_raw($url);
        } else {
            $validated = filter_var($url, FILTER_VALIDATE_URL);
            $url = is_string($validated) ? $validated : '';
        }

        return is_string($url) ? trim($url) : '';
    }

    public static function isAllowed(string $url): bool
    {
        $url = self::normalize($url);
        if ($url === '') {
            return false;
        }

        if (function_exists('wp_http_validate_url') && ! wp_http_validate_url($url)) {
            return false;
        }

        $parts = wp_parse_url($url);
        if (! is_array($parts)) {
            return false;
        }

        $scheme = strtolower((string) ($parts['scheme'] ?? ''));
        if (! in_array($scheme, ['http', 'https'], true)) {
            return false;
        }

        $host = strtolower((string) ($parts['host'] ?? ''));
        if ($host === '' || self::isBlockedHost($host)) {
            return false;
        }

        $ips = self::resolveIps($host);
        if (! $ips) {
            return false;
        }

        foreach ($ips as $ip) {
            if (self::isPrivateOrReserved($ip)) {
                return false;
            }
        }

        return true;
    }

    private static function isBlockedHost(string $host): bool
    {
        if (in_array($host, ['localhost', 'localhost.localdomain'], true)) {
            return true;
        }

        $blockedSuffixes = ['.localhost', '.local', '.internal', '.test'];
        foreach ($blockedSuffixes as $suffix) {
            if (str_ends_with($host, $suffix)) {
                return true;
            }
        }

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

        return false;
    }

    /**
     * @return array<int, string>
     */
    private static function resolveIps(string $host): array
    {
        if (filter_var($host, FILTER_VALIDATE_IP)) {
            return [$host];
        }

        $ips = [];

        if (function_exists('gethostbynamel')) {
            $ipv4 = gethostbynamel($host);
            if (is_array($ipv4)) {
                foreach ($ipv4 as $candidate) {
                    if (is_string($candidate) && filter_var($candidate, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
                        $ips[] = $candidate;
                    }
                }
            }
        }

        if (function_exists('dns_get_record')) {
            $records = dns_get_record($host, DNS_A + DNS_AAAA);
            if (is_array($records)) {
                foreach ($records as $record) {
                    if (! is_array($record)) {
                        continue;
                    }
                    $candidate = '';
                    if (! empty($record['ip']) && is_string($record['ip'])) {
                        $candidate = $record['ip'];
                    } elseif (! empty($record['ipv6']) && is_string($record['ipv6'])) {
                        $candidate = $record['ipv6'];
                    }
                    if ($candidate !== '' && filter_var($candidate, FILTER_VALIDATE_IP)) {
                        $ips[] = $candidate;
                    }
                }
            }
        }

        return array_values(array_unique($ips));
    }

    private static function isPrivateOrReserved(string $ip): bool
    {
        return filter_var(
            $ip,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
        ) === false;
    }
}
