<?php
defined( 'ABSPATH' ) or die( 'No script kiddies please!' );

/**
 * Resolves the client's true IP address by analyzing various server headers.
 * * This function is critical for accurate geolocation. In modern hosting environments,
 * users often sit behind load balancers, reverse proxies (like Nginx), or CDNs (like Cloudflare).
 * Relying solely on 'REMOTE_ADDR' often yields the IP of the proxy server rather than the user.
 * * Logic Order & Precedence:
 * 1. Cloudflare (HTTP_CF_CONNECTING_IP): Highest trust if the site uses Cloudflare.
 * 2. X-Forwarded-For: Standard proxy header. We extract the first IP as it represents the original client.
 * 3. HTTP_X_FORWARDED / HTTP_FORWARDED_FOR: Alternative proxy headers.
 * 4. REMOTE_ADDR: The direct connection IP (fallback if no proxies are involved).
 *
 * @return string The sanitized IP address of the client, or an empty string if detection fails.
 */
function smart_convert_currency_unit_conversion_get_user_ip() {
    if ( ! empty( $_SERVER['HTTP_CF_CONNECTING_IP'] ) ) {
        // Cloudflare real IP header: This is prioritized to prevent spoofing if Cloudflare is active.
        return sanitize_text_field( wp_unslash( $_SERVER['HTTP_CF_CONNECTING_IP'] ) );
    } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
        // Standard proxy header: Can contain a comma-separated list of IPs (Client, Proxy1, Proxy2).
        // Fix for PCP: Sanitize the raw server variable before processing (exploding).
        $forwarded_for = sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED_FOR'] ) );
        
        // We explode the string and take the first element (index 0) to get the original client IP.
        $ips = explode( ',', $forwarded_for );
        return trim( $ips[0] );
    } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED'] ) ) {
        return sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_FORWARDED'] ) );
    } elseif ( ! empty( $_SERVER['HTTP_FORWARDED_FOR'] ) ) {
        return sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED_FOR'] ) );
    } elseif ( ! empty( $_SERVER['HTTP_FORWARDED'] ) ) {
        return sanitize_text_field( wp_unslash( $_SERVER['HTTP_FORWARDED'] ) );
    } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) {
        // Standard non-proxied user IP address: Used for direct server connections.
        return sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) );
    }
    // Return an empty string if no valid IP structure is found in the headers.
    return '';
}

/**
 * Determines the user's country code based on their IP address via the ipinfo.io API.
 * * This function implements a caching strategy (Transients API) to optimize performance
 * and reduce external API costs.
 * * Workflow:
 * 1. Verification: Checks if the "Auto Currency" feature is enabled in plugin settings.
 * 2. Validation: Ensures the IP address is syntactically valid.
 * 3. Cache Check: Looks for an existing valid country code for this IP in the database.
 * 4. API Request: If not cached, queries ipinfo.io (optionally using an API token).
 * 5. Processing: Validates the API response code (200 OK) and structure.
 * 6. Caching: Stores the result for 24 hours to prevent repeated API calls for the same user.
 * * @return string|false Two-letter ISO 3166-1 alpha-2 country code (e.g., 'US', 'DE') or false on failure.
 */
function smart_convert_currency_unit_conversion_get_country_from_ip() {
    // Check if the functionality is enabled in plugin settings to avoid unnecessary processing.
    $options = get_option( 'smart_convert_currency_unit_conversion_option_name' );
    if ( ! isset( $options['auto_currency_from_ip'] ) || $options['auto_currency_from_ip'] !== '1' ) {
        return false;
    }

    $user_ip = smart_convert_currency_unit_conversion_get_user_ip();
    // Validate the retrieved IP address to ensure it is compliant with IPv4 or IPv6 standards.
    if ( empty( $user_ip ) || ! filter_var( $user_ip, FILTER_VALIDATE_IP ) ) {
        return false;
    }

    // Check for cached result in a transient.
    // We use MD5 hashing on the IP to create a consistent, safe, and fixed-length cache key.
    // Cache duration is set to 1 day (DAY_IN_SECONDS) to balance accuracy with performance.
    $cache_key = 'smart_convert_currency_unit_conversion_geo_' . md5( $user_ip );
    $cached = get_transient( $cache_key );
    if ( $cached !== false ) {
        return $cached;
    }

    // Retrieve the API Token from settings (required for higher rate limits on ipinfo.io).
    $api_token = isset($options['smart_convert_currency_unit_conversion_ipinfo_token']) ? trim($options['smart_convert_currency_unit_conversion_ipinfo_token']) : '';

    // Build the endpoint URL for ipinfo.io.
    // Endpoint schema: https://ipinfo.io/{ip}/json
    $url = 'https://ipinfo.io/' . $user_ip . '/json';
    
    // Append the API token to the query string if it exists.
    if ( !empty($api_token) ) {
        $url = add_query_arg('token', $api_token, $url);
    }

    // Execute the remote GET request using WordPress HTTP API.
    // A short timeout (3s) is used to prevent the site from hanging if the API is slow.
    $response = wp_remote_get( $url, array(
        'timeout'   => 3,
        'headers'   => array( 'Accept' => 'application/json' )
    ) );

    // Handle connection errors (e.g., DNS failures, timeouts).
    if ( is_wp_error( $response ) ) {
        return false;
    }

    // Validate the HTTP response code. We only accept a 200 OK status.
    $response_code = wp_remote_retrieve_response_code( $response );
    if ( $response_code !== 200 ) {
        return false;
    }

    // Parse the JSON body.
    $body = wp_remote_retrieve_body( $response );
    $data = json_decode( $body, true );

    // Verify that the 'country' field exists and is not empty.
    if ( ! isset( $data['country'] ) || empty( $data['country'] ) ) {
        return false;
    }

    // Normalize the country code to uppercase for consistency across the application.
    $country_code = strtoupper( $data['country'] );

    // Cache the successfully retrieved country code for this IP.
    set_transient( $cache_key, $country_code, DAY_IN_SECONDS );

    return $country_code;
}

/**
 * Maps a two-letter ISO country code to its corresponding ISO 4217 currency code.
 * * This static mapping avoids the need for an additional API call to determine 
 * currency. It covers a comprehensive list of countries and territories.
 * * Note: While most mappings are stable, some countries may change currencies 
 * due to economic policy changes (e.g., joining the Eurozone). This list 
 * may require periodic updates.
 *
 * @param string $country_code The two-letter ISO 3166-1 country code (e.g., 'GB').
 * @return string The three-letter ISO 4217 currency code (e.g., 'GBP') or 'USD' if not found.
 */
function smart_convert_currency_unit_conversion_get_currency_for_country( $country_code ) {
    // Associative array mapping: Country Code (Key) -> Currency Code (Value).
    $country_to_currency = array(
        'AF' => 'AFN', // Afghanistan
        'AX' => 'EUR', // Åland Islands
        'AL' => 'ALL', // Albania
        'DZ' => 'DZD', // Algeria
        'AS' => 'USD', // American Samoa
        'AD' => 'EUR', // Andorra
        'AO' => 'AOA', // Angola
        'AI' => 'XCD', // Anguilla
        'AQ' => 'USD', // Antarctica
        'AG' => 'XCD', // Antigua and Barbuda
        'AR' => 'ARS', // Argentina
        'AM' => 'AMD', // Armenia
        'AW' => 'AWG', // Aruba
        'AU' => 'AUD', // Australia
        'AT' => 'EUR', // Austria
        'AZ' => 'AZN', // Azerbaijan
        'BS' => 'BSD', // Bahamas
        'BH' => 'BHD', // Bahrain
        'BD' => 'BDT', // Bangladesh
        'BB' => 'BBD', // Barbados
        'BY' => 'BYN', // Belarus
        'BE' => 'EUR', // Belgium
        'BZ' => 'BZD', // Belize
        'BJ' => 'XOF', // Benin
        'BM' => 'BMD', // Bermuda
        'BT' => 'BTN', // Bhutan
        'BO' => 'BOB', // Bolivia
        'BA' => 'BAM', // Bosnia and Herzegovina
        'BW' => 'BWP', // Botswana
        'BV' => 'NOK', // Bouvet Island
        'BR' => 'BRL', // Brazil
        'IO' => 'USD', // British Indian Ocean Territory
        'BN' => 'BND', // Brunei
        'BG' => 'EUR', // Bulgaria
        'BF' => 'XOF', // Burkina Faso
        'BI' => 'BIF', // Burundi
        'KH' => 'KHR', // Cambodia
        'CM' => 'XAF', // Cameroon
        'CA' => 'CAD', // Canada
        'CV' => 'CVE', // Cape Verde
        'KY' => 'KYD', // Cayman Islands
        'CF' => 'XAF', // Central African Republic
        'TD' => 'XAF', // Chad
        'CL' => 'CLP', // Chile
        'CN' => 'CNY', // China
        'CX' => 'AUD', // Christmas Island
        'CC' => 'AUD', // Cocos (Keeling) Islands
        'CO' => 'COP', // Colombia
        'KM' => 'KMF', // Comoros
        'CG' => 'XAF', // Congo
        'CD' => 'CDF', // Congo (Democratic Republic)
        'CK' => 'NZD', // Cook Islands
        'CR' => 'CRC', // Costa Rica
        'CI' => 'XOF', // Côte d'Ivoire
        'HR' => 'HRK', // Croatia
        'CU' => 'CUP', // Cuba
        'CY' => 'EUR', // Cyprus
        'CZ' => 'CZK', // Czech Republic
        'DK' => 'DKK', // Denmark
        'DJ' => 'DJF', // Djibouti
        'DM' => 'XCD', // Dominica
        'DO' => 'DOP', // Dominican Republic
        'EC' => 'USD', // Ecuador
        'EG' => 'EGP', // Egypt
        'SV' => 'USD', // El Salvador
        'GQ' => 'XAF', // Equatorial Guinea
        'ER' => 'ERN', // Eritrea
        'EE' => 'EUR', // Estonia
        'ET' => 'ETB', // Ethiopia
        'FK' => 'FKP', // Falkland Islands
        'FO' => 'DKK', // Faroe Islands
        'FJ' => 'FJD', // Fiji
        'FI' => 'EUR', // Finland
        'FR' => 'EUR', // France
        'GF' => 'EUR', // French Guiana
        'PF' => 'XPF', // French Polynesia
        'TF' => 'EUR', // French Southern Territories
        'GA' => 'XAF', // Gabon
        'GM' => 'GMD', // Gambia
        'GE' => 'GEL', // Georgia
        'DE' => 'EUR', // Germany
        'GH' => 'GHS', // Ghana
        'GI' => 'GIP', // Gibraltar
        'GR' => 'EUR', // Greece
        'GL' => 'DKK', // Greenland
        'GD' => 'XCD', // Grenada
        'GP' => 'EUR', // Guadeloupe
        'GU' => 'USD', // Guam
        'GT' => 'GTQ', // Guatemala
        'GG' => 'GBP', // Guernsey
        'GN' => 'GNF', // Guinea
        'GW' => 'XOF', // Guinea-Bissau
        'GY' => 'GYD', // Guyana
        'HT' => 'HTG', // Haiti
        'HM' => 'AUD', // Heard Island and McDonald Islands
        'HN' => 'HNL', // Honduras
        'HK' => 'HKD', // Hong Kong
        'HU' => 'HUF', // Hungary
        'IS' => 'ISK', // Iceland
        'IN' => 'INR', // India
        'ID' => 'IDR', // Indonesia
        'IR' => 'IRR', // Iran
        'IQ' => 'IQD', // Iraq
        'IE' => 'EUR', // Ireland
        'IM' => 'GBP', // Isle of Man
        'IL' => 'ILS', // Israel
        'IT' => 'EUR', // Italy
        'JM' => 'JMD', // Jamaica
        'JP' => 'JPY', // Japan
        'JE' => 'GBP', // Jersey
        'JO' => 'JOD', // Jordan
        'KZ' => 'KZT', // Kazakhstan
        'KE' => 'KES', // Kenya
        'KI' => 'AUD', // Kiribati
        'KP' => 'KPW', // North Korea
        'KR' => 'KRW', // South Korea
        'KW' => 'KWD', // Kuwait
        'KG' => 'KGS', // Kyrgyzstan
        'LA' => 'LAK', // Laos
        'LV' => 'EUR', // Latvia
        'LB' => 'LBP', // Lebanon
        'LS' => 'LSL', // Lesotho
        'LR' => 'LRD', // Liberia
        'LY' => 'LYD', // Libya
        'LI' => 'CHF', // Liechtenstein
        'LT' => 'EUR', // Lithuania
        'LU' => 'EUR', // Luxembourg
        'MO' => 'MOP', // Macau
        'MK' => 'MKD', // Macedonia
        'MG' => 'MGA', // Madagascar
        'MW' => 'MWK', // Malawi
        'MY' => 'MYR', // Malaysia
        'MV' => 'MVR', // Maldives
        'ML' => 'XOF', // Mali
        'MT' => 'EUR', // Malta
        'MH' => 'USD', // Marshall Islands
        'MQ' => 'EUR', // Martinique
        'MR' => 'MRU', // Mauritania
        'MU' => 'MUR', // Mauritius
        'YT' => 'EUR', // Mayotte
        'MX' => 'MXN', // Mexico
        'FM' => 'USD', // Micronesia
        'MD' => 'MDL', // Moldova
        'MC' => 'EUR', // Monaco
        'MN' => 'MNT', // Mongolia
        'ME' => 'EUR', // Montenegro
        'MS' => 'XCD', // Montserrat
        'MA' => 'MAD', // Morocco
        'MZ' => 'MZN', // Mozambique
        'MM' => 'MMK', // Myanmar
        'NA' => 'NAD', // Namibia
        'NR' => 'AUD', // Nauru
        'NP' => 'NPR', // Nepal
        'NL' => 'EUR', // Netherlands
        'NC' => 'XPF', // New Caledonia
        'NZ' => 'NZD', // New Zealand
        'NI' => 'NIO', // Nicaragua
        'NE' => 'XOF', // Niger
        'NG' => 'NGN', // Nigeria
        'NU' => 'NZD', // Niue
        'NF' => 'AUD', // Norfolk Island
        'MP' => 'USD', // Northern Mariana Islands
        'NO' => 'NOK', // Norway
        'OM' => 'OMR', // Oman
        'PK' => 'PKR', // Pakistan
        'PW' => 'USD', // Palau
        'PS' => 'ILS', // Palestine
        'PA' => 'PAB', // Panama
        'PG' => 'PGK', // Papua New Guinea
        'PY' => 'PYG', // Paraguay
        'PE' => 'PEN', // Peru
        'PH' => 'PHP', // Philippines
        'PN' => 'NZD', // Pitcairn Islands
        'PL' => 'PLN', // Poland
        'PT' => 'EUR', // Portugal
        'PR' => 'USD', // Puerto Rico
        'QA' => 'QAR', // Qatar
        'RE' => 'EUR', // Reunion
        'RO' => 'RON', // Romania
        'RU' => 'RUB', // Russia
        'RW' => 'RWF', // Rwanda
        'BL' => 'EUR', // Saint Barthélemy
        'SH' => 'SHP', // Saint Helena
        'KN' => 'XCD', // Saint Kitts and Nevis
        'LC' => 'XCD', // Saint Lucia
        'MF' => 'EUR', // Saint Martin
        'PM' => 'EUR', // Saint Pierre and Miquelon
        'VC' => 'XCD', // Saint Vincent and the Grenadines
        'WS' => 'WST', // Samoa
        'SM' => 'EUR', // San Marino
        'ST' => 'STN', // São Tomé and Príncipe
        'SA' => 'SAR', // Saudi Arabia
        'SN' => 'XOF', // Senegal
        'RS' => 'RSD', // Serbia
        'SC' => 'SCR', // Seychelles
        'SL' => 'SLE', // Sierra Leone
        'SG' => 'SGD', // Singapore
        'SX' => 'ANG', // Sint Maarten
        'SK' => 'EUR', // Slovakia
        'SI' => 'EUR', // Slovenia
        'SB' => 'SBD', // Solomon Islands
        'SO' => 'SOS', // Somalia
        'ZA' => 'ZAR', // South Africa
        'SS' => 'SSP', // South Sudan
        'ES' => 'EUR', // Spain
        'LK' => 'LKR', // Sri Lanka
        'SD' => 'SDG', // Sudan
        'SR' => 'SRD', // Suriname
        'SJ' => 'NOK', // Svalbard and Jan Mayen
        'SZ' => 'SZL', // Eswatini
        'SE' => 'SEK', // Sweden
        'CH' => 'CHF', // Switzerland
        'SY' => 'SYP', // Syria
        'TW' => 'TWD', // Taiwan
        'TJ' => 'TJS', // Tajikistan
        'TZ' => 'TZS', // Tanzania
        'TH' => 'THB', // Thailand
        'TL' => 'USD', // Timor-Leste
        'TG' => 'XOF', // Togo
        'TK' => 'NZD', // Tokelau
        'TO' => 'TOP', // Tonga
        'TT' => 'TTD', // Trinidad and Tobago
        'TN' => 'TND', // Tunisia
        'TR' => 'TRY', // Turkey
        'TM' => 'TMT', // Turkmenistan
        'TC' => 'USD', // Turks and Caicos Islands
        'TV' => 'AUD', // Tuvalu
        'UG' => 'UGX', // Uganda
        'UA' => 'UAH', // Ukraine
        'AE' => 'AED', // United Arab Emirates
        'GB' => 'GBP', // United Kingdom
        'US' => 'USD', // United States
        'UM' => 'USD', // United States Minor Outlying Islands
        'UY' => 'UYU', // Uruguay
        'UZ' => 'UZS', // Uzbekistan
        'VU' => 'VUV', // Vanuatu
        'VA' => 'EUR', // Vatican City
        'VE' => 'VED', // Venezuela
        'VN' => 'VND', // Vietnam
        'VG' => 'USD', // Virgin Islands (British)
        'VI' => 'USD', // Virgin Islands (U.S.)
        'WF' => 'XPF', // Wallis and Futuna
        'EH' => 'MAD', // Western Sahara
        'YE' => 'YER', // Yemen
        'ZM' => 'ZMW', // Zambia
        'ZW' => 'ZWL', // Zimbabwe
    );

    if ( ! isset( $country_to_currency[ $country_code ] ) ) {
        // Fallback: If the country code is not found in the map (e.g., new country or error), return 'USD'.
        return 'USD';
    }

    return $country_to_currency[ $country_code ];
}

/**
 * Controller function to retrieve the auto-detected currency based on IP.
 * * This function acts as the main entry point (Facade) for the geolocation feature.
 * It orchestrates the process by:
 * 1. Calling `smart_convert_currency_unit_conversion_get_country_from_ip` to identify the location.
 * 2. Calling `smart_convert_currency_unit_conversion_get_currency_for_country` to map that location to a currency.
 * 3. Formatting the result to lowercase to match the plugin's frontend requirements.
 * * @return string|false Lowercase currency code (e.g., 'usd', 'eur') or false if detection fails.
 */
function smart_convert_currency_unit_conversion_get_auto_currency_from_ip() {
    $country_code = smart_convert_currency_unit_conversion_get_country_from_ip();
    if ( ! $country_code ) {
        // Return false if country code retrieval failed (e.g., feature disabled, API error, invalid IP).
        return false;
    }

    $currency = smart_convert_currency_unit_conversion_get_currency_for_country( $country_code );
    // Ensure the returned currency is strictly lowercase for consistency with calling functions.
    return $currency ? strtolower( $currency ) : false;
}
?>