<?php
/**
 * IBAN Validator and Country Code Converter
 * Validates IBAN and converts 2-letter country codes to 3-letter for Bridge
 */

class IBANValidator {
    // Valid SEPA country codes (2-letter to 3-letter mapping)
    private static $sepaCountries = [
        'AT' => 'AUT', // Austria
        'BE' => 'BEL', // Belgium
        'BG' => 'BGR', // Bulgaria
        'HR' => 'HRV', // Croatia
        'CY' => 'CYP', // Cyprus
        'CZ' => 'CZE', // Czech Republic
        'DK' => 'DNK', // Denmark
        'EE' => 'EST', // Estonia
        'FI' => 'FIN', // Finland
        'FR' => 'FRA', // France
        'DE' => 'DEU', // Germany
        'GR' => 'GRC', // Greece
        'HU' => 'HUN', // Hungary
        'IE' => 'IRL', // Ireland
        'IT' => 'ITA', // Italy
        'LV' => 'LVA', // Latvia
        'LT' => 'LTU', // Lithuania
        'LI' => 'LIE', // Liechtenstein
        'LU' => 'LUX', // Luxembourg
        'MT' => 'MLT', // Malta
        'NL' => 'NLD', // Netherlands
        'PL' => 'POL', // Poland
        'PT' => 'PRT', // Portugal
        'RO' => 'ROU', // Romania
        'SK' => 'SVK', // Slovakia
        'SI' => 'SVN', // Slovenia
        'ES' => 'ESP', // Spain
        'SE' => 'SWE', // Sweden
    ];
    
    /**
     * Validate IBAN format and extract country code
     */
    public static function validateIBAN($iban) {
        // Remove ALL whitespace characters including non-breaking spaces (\u00a0, \xC2\xA0)
        $iban = strtoupper(preg_replace('/\s+/', '', trim($iban)));
        // Also explicitly remove non-breaking space characters
        $iban = str_replace(["\xC2\xA0", "\u{00A0}"], '', $iban);
        
        // IBAN must be at least 15 characters
        if (strlen($iban) < 15) {
            return ['valid' => false, 'error' => 'IBAN too short'];
        }
        
        // Extract 2-letter country code
        $countryCode2 = substr($iban, 0, 2);
        
        // Check if country code is valid SEPA country
        if (!isset(self::$sepaCountries[$countryCode2])) {
            return [
                'valid' => false, 
                'error' => 'IBAN does not start with a valid SEPA country code',
                'country_code' => $countryCode2
            ];
        }
        
        // Basic IBAN format validation (mod-97 check)
        if (!self::mod97Check($iban)) {
            return ['valid' => false, 'error' => 'IBAN checksum validation failed'];
        }
        
        // Get 3-letter country code
        $countryCode3 = self::$sepaCountries[$countryCode2];
        
        return [
            'valid' => true,
            'iban' => $iban,
            'country_code_2' => $countryCode2,
            'country_code_3' => $countryCode3,
            'country_name' => self::getCountryName($countryCode2)
        ];
    }
    
    /**
     * Mod-97 check for IBAN validation
     */
    private static function mod97Check($iban) {
        // Move first 4 characters to end
        $rearranged = substr($iban, 4) . substr($iban, 0, 4);
        
        // Replace letters with numbers (A=10, B=11, ..., Z=35)
        $numeric = '';
        for ($i = 0; $i < strlen($rearranged); $i++) {
            $char = $rearranged[$i];
            if (ctype_alpha($char)) {
                $numeric .= (ord($char) - ord('A') + 10);
            } else {
                $numeric .= $char;
            }
        }
        
        // Calculate mod 97
        $remainder = '';
        for ($i = 0; $i < strlen($numeric); $i++) {
            $remainder .= $numeric[$i];
            if (strlen($remainder) >= 9) {
                $remainder = (int)$remainder % 97;
                $remainder = strval($remainder);
            }
        }
        
        return (int)$remainder % 97 === 1;
    }
    
    /**
     * Get country name from 2-letter code
     */
    private static function getCountryName($code2) {
        $names = [
            'AT' => 'Austria',
            'BE' => 'Belgium',
            'BG' => 'Bulgaria',
            'HR' => 'Croatia',
            'CY' => 'Cyprus',
            'CZ' => 'Czech Republic',
            'DK' => 'Denmark',
            'EE' => 'Estonia',
            'FI' => 'Finland',
            'FR' => 'France',
            'DE' => 'Germany',
            'GR' => 'Greece',
            'HU' => 'Hungary',
            'IE' => 'Ireland',
            'IT' => 'Italy',
            'LV' => 'Latvia',
            'LT' => 'Lithuania',
            'LI' => 'Liechtenstein',
            'LU' => 'Luxembourg',
            'MT' => 'Malta',
            'NL' => 'Netherlands',
            'PL' => 'Poland',
            'PT' => 'Portugal',
            'RO' => 'Romania',
            'SK' => 'Slovakia',
            'SI' => 'Slovenia',
            'ES' => 'Spain',
            'SE' => 'Sweden',
        ];
        
        return $names[$code2] ?? $code2;
    }
    
    /**
     * Translate name to English using SYSTRAN Translation API
     * 
     * @param string $name Name to translate
     * @return string Translated name (or original if translation fails)
     */
    public static function translateToEnglish($name) {
        if (empty(trim($name))) {
            return $name;
        }
        
        // Check if SYSTRAN API is available
        if (!class_exists('SystranAPI')) {
            $systranApiPath = __DIR__ . '/systran-api.php';
            if (file_exists($systranApiPath)) {
                require_once $systranApiPath;
            } else {
                error_log("SYSTRAN API class not found. Name translation skipped.");
                return $name; // Return original if SYSTRAN not available
            }
        }
        
        // Get SYSTRAN API key from settings
        $apiKey = self::getSystranApiKey();
        
        if (empty($apiKey)) {
            error_log("SYSTRAN API key not configured. Name translation skipped. Name: $name");
            return $name; // Return original if API key not configured
        }
        
        try {
            $systran = new SystranAPI($apiKey);
            $result = $systran->translateToEnglish($name);
            
            if ($result['success'] && !empty($result['translated_text'])) {
                $translated = $result['translated_text'];
                $detectedLang = $result['detected_language'] ?? 'unknown';
                
                // Only use translation if it's different from original
                if (strtolower(trim($translated)) !== strtolower(trim($name))) {
                    error_log("Name translated: '$name' -> '$translated' (detected language: $detectedLang)");
                    return $translated;
                } else {
                    error_log("Translation returned same as original. Using original name: $name");
                    return $name;
                }
            } else {
                $error = $result['error'] ?? 'Unknown translation error';
                error_log("SYSTRAN translation failed for name '$name': $error. Using original name.");
                return $name; // Return original on error
            }
            
        } catch (Exception $e) {
            error_log("Exception during name translation: " . $e->getMessage() . ". Using original name: $name");
            return $name; // Return original on exception
        }
    }
    
    /**
     * Get SYSTRAN API key from settings
     * 
     * @return string|null API key or null if not configured
     */
    private static function getSystranApiKey() {
        // Try to get from settings if BinanceP2PSettings is available
        if (class_exists('BinanceP2PSettings')) {
            try {
                // We need PDO connection - try to get it from global scope or config
                global $pdo;
                
                if (!isset($pdo) || !($pdo instanceof PDO)) {
                    // Try to load config if not already loaded
                    $configPath = __DIR__ . '/config.php';
                    if (file_exists($configPath)) {
                        require_once $configPath;
                    }
                }
                
                if (isset($pdo) && $pdo instanceof PDO) {
                    $settings = new BinanceP2PSettings($pdo);
                    return $settings->get('systran_api_key');
                }
            } catch (Exception $e) {
                error_log("Error getting SYSTRAN API key from settings: " . $e->getMessage());
            }
        }
        
        // Fallback: try to get from constant or environment variable
        if (defined('SYSTRAN_API_KEY')) {
            return SYSTRAN_API_KEY;
        }
        
        return null;
    }
}

