<?php

namespace App\Modules\Pilkades\Services;

use GeoIp2\Database\Reader;
use Illuminate\Support\Facades\Log;

/**
 * Resolves an IP address to city/province using a local MaxMind GeoLite2
 * database file (no external API calls — shared-hosting friendly, no
 * per-lookup cost). Only city/province level is stored (never precise
 * lat/long) to keep visitor data minimally identifying per UU PDP.
 *
 * The .mmdb file is NOT bundled with the repo (MaxMind requires a free
 * account to download it) — see storage/app/geoip/README.md. If the file
 * is missing, lookups simply return nulls instead of failing the request.
 */
class GeoIpService
{
    protected ?Reader $reader = null;

    protected bool $unavailable = false;

    public function lookup(string $ip): array
    {
        if ($this->isPrivateOrLocal($ip)) {
            return ['kota' => null, 'provinsi' => null];
        }

        $reader = $this->reader();

        if (! $reader) {
            return ['kota' => null, 'provinsi' => null];
        }

        try {
            $record = $reader->city($ip);

            return [
                'kota' => $record->city->name,
                'provinsi' => $record->mostSpecificSubdivision->name,
            ];
        } catch (\Throwable $e) {
            return ['kota' => null, 'provinsi' => null];
        }
    }

    protected function reader(): ?Reader
    {
        if ($this->unavailable) {
            return null;
        }

        if ($this->reader) {
            return $this->reader;
        }

        $path = storage_path('app/geoip/GeoLite2-City.mmdb');

        if (! is_file($path)) {
            $this->unavailable = true;
            Log::debug('GeoIP database not found at '.$path.' — visitor geo lookup disabled.');

            return null;
        }

        return $this->reader = new Reader($path);
    }

    protected function isPrivateOrLocal(string $ip): bool
    {
        return ! filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE);
    }
}
