<?php
class CountryDetector {
    private $sessionKey = 'country_detection_results';

    public function __construct() {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
    }

    public function detectCountry() {
        $methods = [
            'cloudflare' => 'getCountryFromCloudflare',
            'cdn' => 'getCountryFromCDN',
            'api' => 'getCountryFromAPIs',
            'browser' => 'getCountryFromBrowser',
            'server' => 'getCountryFromServer'
        ];

        $results = [];

        foreach ($methods as $methodName => $method) {
            $result = $this->$method();
            $results[$methodName] = [
                'code' => $result,
                'timestamp' => time()
            ];

            $_SESSION[$this->sessionKey][$methodName] = $results[$methodName];

            if ($result) {
                return [
                    'code' => $result,
                    'method' => $methodName,
                    'all_methods' => $results
                ];
            }
        }

        return [
            'code' => null,
            'method' => 'not_detected',
            'all_methods' => $results,
            'error' => 'Could not detect country using any method'
        ];
    }

    // Call specific method by name
    public function callMethod($methodName) {
        $methods = [
            'cloudflare' => 'getCountryFromCloudflare',
            'cdn' => 'getCountryFromCDN',
            'api' => 'getCountryFromAPIs',
            'browser' => 'getCountryFromBrowser',
            'server' => 'getCountryFromServer'
        ];

        if (isset($methods[$methodName])) {
            $method = $methods[$methodName];
            $result = $this->$method();

            $_SESSION[$this->sessionKey][$methodName] = [
                'code' => $result,
                'timestamp' => time()
            ];

            return $result;
        }

        return null;
    }

    // Enable calling detection methods like $detector->cloudflare()
    public function __call($name, $arguments) {
        return $this->callMethod($name);
    }

    // Call multiple specific methods
    public function callMethods($methodNames) {
        $results = [];

        foreach ($methodNames as $methodName) {
            $results[$methodName] = $this->callMethod($methodName);
        }

        return $results;
    }

    // Get all available methods
    public function getAllMethods() {
        return [
            'cloudflare' => 'Cloudflare Headers',
            'cdn' => 'CDN Headers',
            'api' => 'API Geolocation',
            'browser' => 'Browser Language',
            'server' => 'Server Location'
        ];
    }

    private function getCountryFromCloudflare() {
        $headers = [
            'HTTP_CF_IPCOUNTRY',
            'HTTP_CF_IPCOUNTRY_CODE',
            'HTTP_CLOUDFLARE_IPCOUNTRY'
        ];

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $country = strtoupper(trim($_SERVER[$header]));
                if (preg_match('/^[A-Z]{2,3}$/', $country)) {
                    return $country;
                }
            }
        }
        return null;
    }

    private function getCountryFromCDN() {
        $headers = [
            'HTTP_X_COUNTRY_CODE',
            'HTTP_X_GEOIP_COUNTRY',
            'HTTP_X_IPSTACK_COUNTRY_CODE',
            'HTTP_X_IPINFO_COUNTRY',
            'HTTP_GEOIP_COUNTRY_CODE',
            'HTTP_X_APPENGINE_COUNTRY'
        ];

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $country = strtoupper(trim($_SERVER[$header]));
                if (preg_match('/^[A-Z]{2,3}$/', $country)) {
                    return $country;
                }
            }
        }
        return null;
    }

    private function getCountryFromAPIs() {
        $ip = $this->getRealIP();
        if (!$ip || $ip === '127.0.0.1' || $ip === '::1') {
            return null;
        }

        $apis = [
            [
                'url' => "https://ipapi.co/{$ip}/json/",
                'field' => 'country_code'
            ],
            [
                'url' => "https://ipinfo.io/{$ip}/json",
                'field' => 'country'
            ],
            [
                'url' => "http://www.geoplugin.net/json.gp?ip={$ip}",
                'field' => 'geoplugin_countryCode'
            ],
            [
                'url' => "https://api.ipbase.com/v1/json/{$ip}",
                'field' => 'country_code'
            ],
            [
                'url' => "https://api.country.is/{$ip}",
                'field' => 'country'
            ],
            [
                'url' => "https://freeipapi.com/api/json/{$ip}",
                'field' => 'countryCode'
            ]
        ];

        shuffle($apis);

        foreach ($apis as $api) {
            try {
                $country = $this->callAPI($api['url'], $api['field']);
                if ($country) {
                    return $country;
                }
            } catch (Exception $e) {
                continue;
            }

            usleep(50000);
        }

        return null;
    }

    private function getCountryFromBrowser() {
        if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
            $languages = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
            $primaryLang = explode(';', $languages[0])[0];

            if (strpos($primaryLang, '-') !== false) {
                $country = explode('-', $primaryLang)[1];
                if (preg_match('/^[A-Z]{2,3}$/', $country)) {
                    return strtoupper($country);
                }
            }
        }
        return null;
    }

    private function getCountryFromServer() {
        $timezone = @date_default_timezone_get();
        if (strpos($timezone, '/') !== false) {
            $parts = explode('/', $timezone);
            $country = $parts[0];
            if (preg_match('/^[A-Z]{2,3}$/', $country)) {
                return strtoupper($country);
            }
        }
        return null;
    }

    private function callAPI($url, $field) {
        if (function_exists('curl_version')) {
            $ch = curl_init();
            curl_setopt_array($ch, [
                CURLOPT_URL => $url,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_TIMEOUT => 3,
                CURLOPT_SSL_VERIFYPEER => false,
                CURLOPT_USERAGENT => 'Mozilla/5.0 (Country Detector)'
            ]);

            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);

            if ($httpCode === 200 && $response) {
                $data = json_decode($response, true);
                return $this->extractCountryCode($data, $field);
            }
        } else {
            $context = stream_context_create([
                'http' => ['timeout' => 3, 'user_agent' => 'Mozilla/5.0 (Country Detector)'],
                'ssl' => ['verify_peer' => false]
            ]);

            $response = @file_get_contents($url, false, $context);
            if ($response) {
                $data = json_decode($response, true);
                return $this->extractCountryCode($data, $field);
            }
        }

        return null;
    }

    private function extractCountryCode($data, $field) {
        if (!$data) return null;

        $keys = explode('.', $field);
        $value = $data;

        foreach ($keys as $key) {
            if (!isset($value[$key])) {
                return null;
            }
            $value = $value[$key];
        }

        if (is_string($value) && preg_match('/^[A-Z]{2,3}$/', $value)) {
            return strtoupper($value);
        }

        return null;
    }

    private function getRealIP() {
        $headers = [
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_REAL_IP',
            'HTTP_CLIENT_IP',
            'HTTP_X_CLUSTER_CLIENT_IP',
            'HTTP_FORWARDED_FOR',
            'HTTP_FORWARDED',
            'REMOTE_ADDR'
        ];

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ips = explode(',', $_SERVER[$header]);
                foreach ($ips as $ip) {
                    $ip = trim($ip);
                    if (filter_var($ip, FILTER_VALIDATE_IP)) {
                        return $ip;
                    }
                }
            }
        }

        return $_SERVER['REMOTE_ADDR'] ?? null;
    }

    public function getSessionResults() {
        return $_SESSION[$this->sessionKey] ?? [];
    }

    public function clearSessionResults() {
        unset($_SESSION[$this->sessionKey]);
    }

    public function getLastDetection() {
        $results = $this->getSessionResults();
        if (empty($results)) {
            return null;
        }

        foreach ($results as $method => $data) {
            if (!empty($data['code'])) {
                return [
                    'code' => $data['code'],
                    'method' => $method,
                    'timestamp' => $data['timestamp']
                ];
            }
        }

        return null;
    }

    public function getMethodResult($methodName) {
        $results = $this->getSessionResults();
        return $results[$methodName] ?? null;
    }

    public function getCountryCode() {
        $lastDetection = $this->getLastDetection();
        if ($lastDetection) {
            return $lastDetection['code'];
        }

        $result = $this->detectCountry();
        return $result['code'];
    }
}

$detector = new CountryDetector();
$detector->api();