<?php

namespace FleekDash\Services\AnalyticsTracking;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

/**
 * GeoIP Processor
 *
 * Handles IP geolocation using multiple providers with fallback
 *
 * @package FleekDash\Services\AnalyticsTracking
 */
class GeoIPProcessor
{
    /**
     * Get geo data from IP using multiple providers with fallback
     *
     * @param string $ip_address IP address to lookup
     * @return array Country code, name, city
     */
    public static function getGeoData($ip_address)
    {
        // Skip for local/private IPs
        if (empty($ip_address) || $ip_address === '127.0.0.1' || $ip_address === '::1' ||
            filter_var($ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
            return [
                'country_code' => 'XX',
                'country_name' => 'Local/Private',
                'city' => 'Unknown'
            ];
        }

        // Check cache first
        $cache_key = 'fleekdash_geoip_' . md5($ip_address);
        $cached = \get_transient($cache_key);
        if ($cached !== false) {
            return $cached;
        }

        // Try multiple GeoIP providers with fallback
        $geo_data = self::tryGeoIPProviders($ip_address);

        // Cache for 24 hours
        \set_transient($cache_key, $geo_data, 24 * HOUR_IN_SECONDS);

        return $geo_data;
    }

    /**
     * Try multiple GeoIP providers with fallback
     *
     * @param string $ip_address IP address
     * @return array Geo data
     */
    private static function tryGeoIPProviders($ip_address)
    {
        $providers = [
            'ipapi' => "http://ip-api.com/json/{$ip_address}?fields=status,country,countryCode,city,regionName",
            'ipinfo' => "https://ipinfo.io/{$ip_address}/json",
            'freegeoip' => "https://freegeoip.app/json/{$ip_address}"
        ];

        foreach ($providers as $provider => $url) {
            try {
                $response = \wp_remote_get($url, ['timeout' => 2, 'sslverify' => false]);

                if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
                    $body = wp_remote_retrieve_body($response);
                    $data = json_decode($body, true);

                    if ($data && self::validateGeoIPResponse($data, $provider)) {
                        return self::normalizeGeoIPData($data, $provider);
                    }
                }
            } catch (\Exception $e) {
                // Log error but continue to next provider
                fleekdash_log_debug("FleekDash GeoIP: {$provider} failed - " . $e->getMessage());
            }
        }

        // Fallback if all providers fail
        return [
            'country_code' => 'XX',
            'country_name' => 'Unknown',
            'city' => 'Unknown'
        ];
    }

    /**
     * Validate GeoIP response based on provider
     *
     * @param array $data Response data
     * @param string $provider Provider name
     * @return bool Valid or not
     */
    private static function validateGeoIPResponse($data, $provider)
    {
        switch ($provider) {
            case 'ipapi':
                return isset($data['status']) && $data['status'] === 'success';
            case 'ipinfo':
                return isset($data['country']) && !isset($data['error']);
            case 'freegeoip':
                return isset($data['country_code']);
            default:
                return false;
        }
    }

    /**
     * Normalize GeoIP data from different providers
     *
     * @param array $data Provider response
     * @param string $provider Provider name
     * @return array Normalized geo data
     */
    private static function normalizeGeoIPData($data, $provider)
    {
        switch ($provider) {
            case 'ipapi':
                return [
                    'country_code' => $data['countryCode'] ?? 'XX',
                    'country_name' => $data['country'] ?? 'Unknown',
                    'city' => $data['city'] ?? 'Unknown',
                    'region' => $data['regionName'] ?? null
                ];
            case 'ipinfo':
                return [
                    'country_code' => $data['country'] ?? 'XX',
                    'country_name' => self::getCountryNameFromCode($data['country'] ?? 'XX'),
                    'city' => $data['city'] ?? 'Unknown',
                    'region' => $data['region'] ?? null
                ];
            case 'freegeoip':
                return [
                    'country_code' => $data['country_code'] ?? 'XX',
                    'country_name' => $data['country_name'] ?? 'Unknown',
                    'city' => $data['city'] ?? 'Unknown',
                    'region' => $data['region_name'] ?? null
                ];
            default:
                return [
                    'country_code' => 'XX',
                    'country_name' => 'Unknown',
                    'city' => 'Unknown'
                ];
        }
    }

    /**
     * Get country name from country code
     *
     * @param string $code Country code (ISO 3166-1 alpha-2)
     * @return string Country name
     */
    public static function getCountryNameFromCode($code)
    {
        $countries = [
            'US' => 'United States', 'CA' => 'Canada', 'GB' => 'United Kingdom',
            'DE' => 'Germany', 'FR' => 'France', 'IT' => 'Italy', 'ES' => 'Spain',
            'BR' => 'Brazil', 'MX' => 'Mexico', 'AR' => 'Argentina', 'CL' => 'Chile',
            'AU' => 'Australia', 'NZ' => 'New Zealand', 'JP' => 'Japan', 'CN' => 'China',
            'IN' => 'India', 'RU' => 'Russia', 'ZA' => 'South Africa', 'EG' => 'Egypt',
            'NG' => 'Nigeria', 'KE' => 'Kenya', 'XX' => 'Unknown'
        ];

        return $countries[$code] ?? 'Unknown';
    }
}
