<?php
declare(strict_types=1);

namespace App\Infrastructure\GeoIp;

use App\Framework\Http\IpAddress;
use PDO;

final class GeoIp
{
    private readonly PDO $database;
    private readonly IpRangeService $ipRangeService;
    private readonly CountryDataService $countryDataService;

    public function __construct(?string $databasePath = null)
    {
        $databasePath = $databasePath ?? __DIR__ . '/data/ip_country.sqlite';
        $this->database = $this->initializeDatabase($databasePath);
        $this->ipRangeService = new IpRangeService($this->database);
        $this->countryDataService = new CountryDataService($this->database);
    }

    /**
     * @deprecated Use DatabaseSetup::setupCompleteDatabase() instead
     */
    public function loadDatabase(): void
    {
        $setup = new DatabaseSetup(__DIR__ . '/data/ip_country.sqlite');
        $setup->setupIpRangesOnly();
    }

    public function getCountryForString(string $ip): ?string
    {
        return $this->ipRangeService->getCountryCodeForIp($ip);
    }

    public function getCountryForIp(IpAddress $ipAddress): ?string
    {
        if ($ipAddress->isPrivate()) {
            return null;
        }

        return $this->getCountryForString($ipAddress->value);
    }

    public function getCountryInfo(string $ip): CountryInfo
    {
        $countryCode = $this->getCountryForString($ip);

        if (!$countryCode) {
            return new CountryInfo($ip, null);
        }

        $country = $this->countryDataService->getCountryByCode($countryCode);

        return new CountryInfo($ip, $countryCode, $country);
    }

    public function getCountryInfoForIp(IpAddress $ipAddress): CountryInfo
    {
        if ($ipAddress->isPrivate()) {
            return new CountryInfo($ipAddress->value, null);
        }

        return $this->getCountryInfo($ipAddress->value);
    }

    public function getCountryNameGerman(string $ip): ?string
    {
        return $this->getCountryInfo($ip)->getGermanName();
    }

    public function getCountryNameEnglish(string $ip): ?string
    {
        return $this->getCountryInfo($ip)->getEnglishName();
    }

    public function getCountryNameNative(string $ip): ?string
    {
        return $this->getCountryInfo($ip)->getNativeName();
    }

    private function initializeDatabase(string $file): PDO
    {
        $directory = dirname($file);
        if (!is_dir($directory)) {
            mkdir($directory, 0755, true);
        }

        $db = new PDO('sqlite:' . $file);
        $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        // IP-Ranges Tabelle
        $db->exec('CREATE TABLE IF NOT EXISTS ip_ranges (
            id INTEGER PRIMARY KEY,
            ip_start INTEGER,
            ip_end INTEGER,
            country TEXT
        )');
        $db->exec('CREATE INDEX IF NOT EXISTS idx_ip_range ON ip_ranges (ip_start, ip_end)');

        // Länder-Tabelle für ISO-Daten
        $db->exec('CREATE TABLE IF NOT EXISTS countries (
            code TEXT PRIMARY KEY,
            name_en TEXT,
            name_de TEXT,
            name_native TEXT,
            updated_at TEXT
        )');

        return $db;
    }
}
