<?php

declare(strict_types=1);

namespace app\common\service;

use GeoIp2\Database\Reader;
use GeoIp2\Exception\AddressNotFoundException;

/**
 * 基于 GeoLite2-Country.mmdb 的 IP 国家查询（MaxMind GeoIP2）
 */
class SplitGeoIpService
{
    /** 项目根目录下的 MaxMind 国家库文件名 */
    private const DB_FILENAME = 'GeoLite2-Country.mmdb';

    private static ?Reader $reader = null;

    /**
     * 解析 IP 对应 ISO 3166-1 alpha-2 国家代码；无法解析时返回 null
     */
    public static function getCountryIso2(string $ip): ?string
    {
        $ip = trim($ip);
        if ($ip === '' || filter_var($ip, FILTER_VALIDATE_IP) === false) {
            return null;
        }

        self::bootstrapLibrary();

        try {
            $record = self::getReader()->country($ip);
            $code = $record->country->isoCode ?? null;
            if (!is_string($code) || $code === '') {
                return null;
            }

            return strtoupper($code);
        } catch (AddressNotFoundException $e) {
            return null;
        } catch (\Throwable $e) {
            return null;
        }
    }

    /**
     * MMDB 绝对路径
     */
    public static function getDatabasePath(): string
    {
        return rtrim((string) ROOT_PATH, '/\\') . DIRECTORY_SEPARATOR . self::DB_FILENAME;
    }

    public static function isDatabaseAvailable(): bool
    {
        $path = self::getDatabasePath();

        return is_file($path) && is_readable($path);
    }

    private static function bootstrapLibrary(): void
    {
        static $bootstrapped = false;
        if ($bootstrapped) {
            return;
        }
        $bootstrapped = true;
        $loader = ROOT_PATH . 'patches/third_party/load_geoip2.php';
        if (is_file($loader)) {
            require_once $loader;
        }
    }

    private static function getReader(): Reader
    {
        if (self::$reader instanceof Reader) {
            return self::$reader;
        }
        if (!self::isDatabaseAvailable()) {
            throw new \RuntimeException('GeoLite2-Country.mmdb not readable at project root');
        }
        self::$reader = new Reader(self::getDatabasePath());

        return self::$reader;
    }
}
