<?php

namespace Modules\SmartStorage\Entities\Services;

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

/**
 * Resolves an IP address to a coarse location for the access log.
 *
 * Default provider is "none" (offline / privacy-preserving). When set to
 * "ip-api" it performs a cached lookup against the free ip-api.com endpoint.
 * Private/loopback IPs always resolve to null. Failures degrade silently —
 * geo data is best-effort metadata, never a hard dependency.
 */
class GeoResolver
{
    /**
     * @return array{country:?string,city:?string,lat:?float,lng:?float}
     */
    public function resolve(?string $ip): array
    {
        $empty = ['country' => null, 'city' => null, 'lat' => null, 'lng' => null];

        if (empty($ip) || !filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
            return $empty;
        }

        $provider = optionalSetting('geo_provider', 'none');
        if ($provider !== 'ip-api') {
            return $empty;
        }

        try {
            return Cache::remember('ss_geo_' . $ip, now()->addDays(7), function () use ($ip, $empty) {
                $resp = Http::timeout(3)->get("http://ip-api.com/json/{$ip}", [
                    'fields' => 'status,country,city,lat,lon',
                ]);
                if (!$resp->ok() || ($resp->json('status') !== 'success')) {
                    return $empty;
                }
                return [
                    'country' => $resp->json('country'),
                    'city'    => $resp->json('city'),
                    'lat'     => $resp->json('lat'),
                    'lng'     => $resp->json('lon'),
                ];
            });
        } catch (\Throwable $e) {
            return $empty;
        }
    }
}

if (!function_exists('Modules\SmartStorage\Entities\Services\optionalSetting')) {
    /**
     * Tiny local helper so GeoResolver doesn't hard-depend on a loaded settings
     * row during early boot.
     */
    function optionalSetting(string $key, $default = null)
    {
        try {
            return \Modules\SmartStorage\Entities\SsSetting::current()->{$key} ?? $default;
        } catch (\Throwable $e) {
            return $default;
        }
    }
}
