<?php

namespace App\Support;

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Http;

/**
 * Resolve a visitor's ISO country code from their IP address.
 *
 * Order of preference:
 *   1. A trusted Cloudflare/proxy country header (only when TRUST_CLOUDFLARE=1).
 *   2. A cached GeoIP lookup against a free geolocation service.
 *
 * Every failure path returns null so that offer browsing degrades to
 * "show everything" rather than breaking.
 */
class GeoLocation
{
    public static function countryForRequest(): ?string
    {
        if ($header = request_country_code()) {
            return $header;
        }

        return self::countryForIp(ip());
    }

    public static function countryForIp(?string $ip): ?string
    {
        $ip = trim((string) $ip);

        if ($ip === '' || self::isPrivateIp($ip)) {
            return null;
        }

        return Cache::remember('geoip:'.$ip, now()->addHours(24), function () use ($ip) {
            return self::lookup($ip);
        });
    }

    private static function lookup(string $ip): ?string
    {
        try {
            $response = Http::timeout(3)->get("http://ip-api.com/json/{$ip}", [
                'fields' => 'status,countryCode',
            ]);

            if (!$response->ok() || $response->json('status') !== 'success') {
                return null;
            }

            $country = strtoupper(trim((string) $response->json('countryCode')));

            return $country !== '' ? $country : null;
        } catch (\Throwable $exception) {
            return null;
        }
    }

    private static function isPrivateIp(string $ip): bool
    {
        // Loopback / private / reserved ranges never geolocate to a country.
        return filter_var(
            $ip,
            FILTER_VALIDATE_IP,
            FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
        ) === false;
    }
}
