<?php
/**
 * PFA Fuzzy Matching Engine
 * Real-time fuzzy matching with phonetic similarity and accent variation handling
 * 
 * Features:
 * - Levenshtein distance matching
 * - Soundex phonetic matching
 * - Metaphone phonetic matching
 * - Accent/diacritic normalization
 * - Name variation detection
 * - Configurable threshold matching
 */

header('Content-Type: application/json');
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);

// Database Configuration
define('DB_HOST', 'localhost');
define('DB_NAME', 'i4urunplace_xml');
define('DB_USER', 'i4urunplace_xml');
define('DB_PASS', 'SEMZtyETGL8B');

class FuzzyMatcher {
    private $pdo;
    private $config;
    
    public function __construct($dbHost, $dbName, $dbUser, $dbPass) {
        $this->connectDatabase($dbHost, $dbName, $dbUser, $dbPass);
        $this->initializeConfig();
    }
    
    private function connectDatabase($host, $dbName, $user, $pass) {
        try {
            $dsn = "mysql:host=$host;dbname=$dbName;charset=utf8mb4";
            $options = [
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
                PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
                PDO::ATTR_EMULATE_PREPARES => false,
            ];
            $this->pdo = new PDO($dsn, $user, $pass, $options);
        } catch (PDOException $e) {
            throw new Exception('Database connection failed: ' . $e->getMessage());
        }
    }
    
    private function initializeConfig() {
        // Matching thresholds
        $this->config = [
            'exact_threshold' => 100,           // 100% match
            'high_threshold' => 90,             // 90%+ match (very likely)
            'medium_threshold' => 75,           // 75-89% match (possible)
            'low_threshold' => 60,              // 60-74% match (uncertain)
            'phonetic_weight' => 0.3,           // Weight for phonetic similarity
            'levenshtein_weight' => 0.4,        // Weight for edit distance
            'token_weight' => 0.3,              // Weight for token matching
            'max_results' => 50,                // Maximum results to return
            'min_score' => 60                   // Minimum score to consider
        ];
    }
    
    /**
     * Main search function - handles different search types
     */
    public function search($searchTerm, $searchType = 'name', $options = []) {
        $searchTerm = trim($searchTerm);
        
        if (empty($searchTerm)) {
            return ['success' => false, 'error' => 'Search term is required'];
        }
        
        // Merge options with defaults
        $options = array_merge([
            'include_fuzzy' => true,
            'include_phonetic' => true,
            'min_score' => $this->config['min_score'],
            'max_results' => $this->config['max_results']
        ], $options);
        
        switch ($searchType) {
            case 'name':
                return $this->searchByName($searchTerm, $options);
            case 'full_name':
                return $this->searchByFullName($searchTerm, $options);
            case 'nationality':
                return $this->searchByNationality($searchTerm, $options);
            case 'all':
                return $this->searchAll($searchTerm, $options);
            default:
                return ['success' => false, 'error' => 'Invalid search type'];
        }
    }
    
    /**
     * Search by name (first name or surname)
     */
    private function searchByName($searchTerm, $options) {
        $normalized = $this->normalizeText($searchTerm);
        $soundex = soundex($searchTerm);
        $metaphone = metaphone($searchTerm);
        
        // Build query for candidates
        $sql = "SELECT 
                    id,
                    external_id,
                    first_name,
                    middle_name,
                    surname,
                    single_string_name,
                    nationality,
                    date_of_birth,
                    active_status,
                    deceased
                FROM pfa_records
                WHERE 
                    first_name LIKE :search1 OR
                    surname LIKE :search2 OR
                    middle_name LIKE :search3 OR
                    single_string_name LIKE :search4 OR
                    SOUNDEX(first_name) = :soundex1 OR
                    SOUNDEX(surname) = :soundex2
                LIMIT 500";
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->execute([
            'search1' => "%{$normalized}%",
            'search2' => "%{$normalized}%",
            'search3' => "%{$normalized}%",
            'search4' => "%{$normalized}%",
            'soundex1' => $soundex,
            'soundex2' => $soundex
        ]);
        
        $candidates = $stmt->fetchAll();
        
        // Score and rank candidates
        $results = $this->scoreNameCandidates($searchTerm, $candidates, $options);
        
        // Sort by score descending
        usort($results, function($a, $b) {
            return $b['match_score'] <=> $a['match_score'];
        });
        
        // Apply limits
        $results = array_slice($results, 0, $options['max_results']);
        
        return [
            'success' => true,
            'search_term' => $searchTerm,
            'search_type' => 'name',
            'total_candidates' => count($candidates),
            'matched_results' => count($results),
            'results' => $results
        ];
    }
    
    /**
     * Search by full name (handles multiple name parts)
     */
    private function searchByFullName($searchTerm, $options) {
        $normalized = $this->normalizeText($searchTerm);
        $nameParts = $this->parseNameParts($searchTerm);
        
        // Build dynamic query based on name parts
        $sql = "SELECT 
                    id,
                    external_id,
                    first_name,
                    middle_name,
                    surname,
                    single_string_name,
                    nationality,
                    date_of_birth,
                    active_status,
                    deceased
                FROM pfa_records
                WHERE 
                    single_string_name LIKE :search1";
        
        // Add individual name part searches
        if (!empty($nameParts['first'])) {
            $sql .= " OR first_name LIKE :first";
        }
        if (!empty($nameParts['last'])) {
            $sql .= " OR surname LIKE :last";
        }
        
        $sql .= " LIMIT 500";
        
        $stmt = $this->pdo->prepare($sql);
        
        $params = ['search1' => "%{$normalized}%"];
        if (!empty($nameParts['first'])) {
            $params['first'] = "%{$nameParts['first']}%";
        }
        if (!empty($nameParts['last'])) {
            $params['last'] = "%{$nameParts['last']}%";
        }
        
        $stmt->execute($params);
        $candidates = $stmt->fetchAll();
        
        // Score candidates
        $results = $this->scoreFullNameCandidates($searchTerm, $nameParts, $candidates, $options);
        
        // Sort and limit
        usort($results, function($a, $b) {
            return $b['match_score'] <=> $a['match_score'];
        });
        
        $results = array_slice($results, 0, $options['max_results']);
        
        return [
            'success' => true,
            'search_term' => $searchTerm,
            'search_type' => 'full_name',
            'parsed_name' => $nameParts,
            'total_candidates' => count($candidates),
            'matched_results' => count($results),
            'results' => $results
        ];
    }
    
    /**
     * Search by nationality
     */
    private function searchByNationality($searchTerm, $options) {
        $normalized = $this->normalizeText($searchTerm);
        
        $sql = "SELECT 
                    id,
                    external_id,
                    first_name,
                    middle_name,
                    surname,
                    single_string_name,
                    nationality,
                    date_of_birth,
                    active_status,
                    deceased
                FROM pfa_records
                WHERE nationality LIKE :search
                LIMIT :limit";
        
        $stmt = $this->pdo->prepare($sql);
        $stmt->bindValue('search', "%{$normalized}%", PDO::PARAM_STR);
        $stmt->bindValue('limit', $options['max_results'], PDO::PARAM_INT);
        $stmt->execute();
        
        $results = $stmt->fetchAll();
        
        return [
            'success' => true,
            'search_term' => $searchTerm,
            'search_type' => 'nationality',
            'matched_results' => count($results),
            'results' => $results
        ];
    }
    
    /**
     * Search across all fields
     */
    private function searchAll($searchTerm, $options) {
        $normalized = $this->normalizeText($searchTerm);
        
        $sql = "SELECT 
                    id,
                    external_id,
                    first_name,
                    middle_name,
                    surname,
                    single_string_name,
                    nationality,
                    date_of_birth,
                    active_status,
                    deceased,
                    occupation,
                    address
                FROM pfa_records
                WHERE 
                    first_name LIKE :search1 OR
                    middle_name LIKE :search2 OR
                    surname LIKE :search3 OR
                    single_string_name LIKE :search4 OR
                    nationality LIKE :search5 OR
                    occupation LIKE :search6 OR
                    address LIKE :search7
                LIMIT 500";
        
        $stmt = $this->pdo->prepare($sql);
        $searchPattern = "%{$normalized}%";
        $stmt->execute([
            'search1' => $searchPattern,
            'search2' => $searchPattern,
            'search3' => $searchPattern,
            'search4' => $searchPattern,
            'search5' => $searchPattern,
            'search6' => $searchPattern,
            'search7' => $searchPattern
        ]);
        
        $candidates = $stmt->fetchAll();
        
        // Score candidates
        $results = $this->scoreAllFieldsCandidates($searchTerm, $candidates, $options);
        
        usort($results, function($a, $b) {
            return $b['match_score'] <=> $a['match_score'];
        });
        
        $results = array_slice($results, 0, $options['max_results']);
        
        return [
            'success' => true,
            'search_term' => $searchTerm,
            'search_type' => 'all',
            'total_candidates' => count($candidates),
            'matched_results' => count($results),
            'results' => $results
        ];
    }
    
    /**
     * Score name candidates with fuzzy matching
     */
    private function scoreNameCandidates($searchTerm, $candidates, $options) {
        $results = [];
        $searchNormalized = $this->normalizeText($searchTerm);
        $searchSoundex = soundex($searchTerm);
        $searchMetaphone = metaphone($searchTerm);
        
        foreach ($candidates as $candidate) {
            $scores = [];
            $matchedFields = [];
            
            // Check first name
            if (!empty($candidate['first_name'])) {
                $score = $this->calculateSimilarity(
                    $searchNormalized,
                    $this->normalizeText($candidate['first_name']),
                    $searchSoundex,
                    $searchMetaphone
                );
                
                if ($score >= $options['min_score']) {
                    $scores[] = $score;
                    $matchedFields[] = 'first_name';
                }
            }
            
            // Check surname
            if (!empty($candidate['surname'])) {
                $score = $this->calculateSimilarity(
                    $searchNormalized,
                    $this->normalizeText($candidate['surname']),
                    $searchSoundex,
                    $searchMetaphone
                );
                
                if ($score >= $options['min_score']) {
                    $scores[] = $score;
                    $matchedFields[] = 'surname';
                }
            }
            
            // Check middle name
            if (!empty($candidate['middle_name'])) {
                $score = $this->calculateSimilarity(
                    $searchNormalized,
                    $this->normalizeText($candidate['middle_name']),
                    $searchSoundex,
                    $searchMetaphone
                );
                
                if ($score >= $options['min_score']) {
                    $scores[] = $score;
                    $matchedFields[] = 'middle_name';
                }
            }
            
            // Check full name
            if (!empty($candidate['single_string_name'])) {
                $score = $this->calculateSimilarity(
                    $searchNormalized,
                    $this->normalizeText($candidate['single_string_name']),
                    $searchSoundex,
                    $searchMetaphone
                );
                
                if ($score >= $options['min_score']) {
                    $scores[] = $score;
                    $matchedFields[] = 'single_string_name';
                }
            }
            
            // If we have matches, add to results
            if (!empty($scores)) {
                $maxScore = max($scores);
                
                $results[] = [
                    'id' => $candidate['id'],
                    'external_id' => $candidate['external_id'],
                    'first_name' => $candidate['first_name'],
                    'middle_name' => $candidate['middle_name'],
                    'surname' => $candidate['surname'],
                    'single_string_name' => $candidate['single_string_name'],
                    'nationality' => $candidate['nationality'],
                    'date_of_birth' => $candidate['date_of_birth'],
                    'active_status' => $candidate['active_status'],
                    'deceased' => $candidate['deceased'],
                    'match_score' => round($maxScore, 2),
                    'match_confidence' => $this->getConfidenceLevel($maxScore),
                    'matched_fields' => $matchedFields,
                    'all_scores' => array_map(function($s) { return round($s, 2); }, $scores)
                ];
            }
        }
        
        return $results;
    }
    
    /**
     * Score full name candidates
     */
    private function scoreFullNameCandidates($searchTerm, $nameParts, $candidates, $options) {
        $results = [];
        $searchNormalized = $this->normalizeText($searchTerm);
        
        foreach ($candidates as $candidate) {
            $scores = [];
            $details = [];
            
            // Full name comparison
            if (!empty($candidate['single_string_name'])) {
                $fullNameScore = $this->calculateSimilarity(
                    $searchNormalized,
                    $this->normalizeText($candidate['single_string_name']),
                    soundex($searchTerm),
                    metaphone($searchTerm)
                );
                $scores['full_name'] = $fullNameScore;
            }
            
            // Individual name part comparison
            if (!empty($nameParts['first']) && !empty($candidate['first_name'])) {
                $firstScore = $this->calculateSimilarity(
                    $this->normalizeText($nameParts['first']),
                    $this->normalizeText($candidate['first_name']),
                    soundex($nameParts['first']),
                    metaphone($nameParts['first'])
                );
                $scores['first_name'] = $firstScore;
            }
            
            if (!empty($nameParts['last']) && !empty($candidate['surname'])) {
                $lastScore = $this->calculateSimilarity(
                    $this->normalizeText($nameParts['last']),
                    $this->normalizeText($candidate['surname']),
                    soundex($nameParts['last']),
                    metaphone($nameParts['last'])
                );
                $scores['surname'] = $lastScore;
            }
            
            // Calculate composite score
            $compositeScore = !empty($scores) ? max($scores) : 0;
            
            // Bonus if multiple parts match
            if (count($scores) > 1) {
                $avgScore = array_sum($scores) / count($scores);
                $compositeScore = ($compositeScore * 0.7) + ($avgScore * 0.3);
            }
            
            if ($compositeScore >= $options['min_score']) {
                $results[] = [
                    'id' => $candidate['id'],
                    'external_id' => $candidate['external_id'],
                    'first_name' => $candidate['first_name'],
                    'middle_name' => $candidate['middle_name'],
                    'surname' => $candidate['surname'],
                    'single_string_name' => $candidate['single_string_name'],
                    'nationality' => $candidate['nationality'],
                    'date_of_birth' => $candidate['date_of_birth'],
                    'active_status' => $candidate['active_status'],
                    'deceased' => $candidate['deceased'],
                    'match_score' => round($compositeScore, 2),
                    'match_confidence' => $this->getConfidenceLevel($compositeScore),
                    'score_breakdown' => array_map(function($s) { return round($s, 2); }, $scores)
                ];
            }
        }
        
        return $results;
    }
    
    /**
     * Score candidates across all fields
     */
    private function scoreAllFieldsCandidates($searchTerm, $candidates, $options) {
        $results = [];
        $searchNormalized = $this->normalizeText($searchTerm);
        
        foreach ($candidates as $candidate) {
            $bestScore = 0;
            $matchedField = '';
            
            $fields = [
                'first_name',
                'middle_name',
                'surname',
                'single_string_name',
                'nationality',
                'occupation',
                'address'
            ];
            
            foreach ($fields as $field) {
                if (!empty($candidate[$field])) {
                    $score = $this->calculateSimilarity(
                        $searchNormalized,
                        $this->normalizeText($candidate[$field]),
                        soundex($searchTerm),
                        metaphone($searchTerm)
                    );
                    
                    if ($score > $bestScore) {
                        $bestScore = $score;
                        $matchedField = $field;
                    }
                }
            }
            
            if ($bestScore >= $options['min_score']) {
                $results[] = [
                    'id' => $candidate['id'],
                    'external_id' => $candidate['external_id'],
                    'first_name' => $candidate['first_name'],
                    'middle_name' => $candidate['middle_name'],
                    'surname' => $candidate['surname'],
                    'single_string_name' => $candidate['single_string_name'],
                    'nationality' => $candidate['nationality'],
                    'date_of_birth' => $candidate['date_of_birth'],
                    'active_status' => $candidate['active_status'],
                    'deceased' => $candidate['deceased'],
                    'occupation' => $candidate['occupation'],
                    'address' => $candidate['address'],
                    'match_score' => round($bestScore, 2),
                    'match_confidence' => $this->getConfidenceLevel($bestScore),
                    'matched_field' => $matchedField
                ];
            }
        }
        
        return $results;
    }
    
    /**
     * Calculate similarity score between two strings
     * Uses combination of Levenshtein distance, phonetic matching, and token matching
     */
    private function calculateSimilarity($str1, $str2, $soundex1, $soundex2) {
        // Exact match
        if ($str1 === $str2) {
            return 100;
        }
        
        // Levenshtein distance score
        $levenshtein = $this->levenshteinSimilarity($str1, $str2);
        
        // Phonetic similarity
        $phonetic = $this->phoneticSimilarity($str1, $str2, $soundex1, $soundex2);
        
        // Token-based similarity
        $token = $this->tokenSimilarity($str1, $str2);
        
        // Weighted composite score
        $compositeScore = 
            ($levenshtein * $this->config['levenshtein_weight']) +
            ($phonetic * $this->config['phonetic_weight']) +
            ($token * $this->config['token_weight']);
        
        return $compositeScore;
    }
    
    /**
     * Calculate Levenshtein distance similarity as percentage
     */
    private function levenshteinSimilarity($str1, $str2) {
        $maxLen = max(strlen($str1), strlen($str2));
        
        if ($maxLen == 0) {
            return 100;
        }
        
        $distance = levenshtein($str1, $str2);
        $similarity = (1 - ($distance / $maxLen)) * 100;
        
        return max(0, $similarity);
    }
    
    /**
     * Calculate phonetic similarity using Soundex and Metaphone
     */
    private function phoneticSimilarity($str1, $str2, $soundex1 = null, $soundex2 = null) {
        $score = 0;
        
        // Soundex comparison
        $soundex1 = $soundex1 ?? soundex($str1);
        $soundex2 = soundex($str2);
        
        if ($soundex1 === $soundex2) {
            $score += 50;
        }
        
        // Metaphone comparison
        $metaphone1 = metaphone($str1);
        $metaphone2 = metaphone($str2);
        
        if ($metaphone1 === $metaphone2) {
            $score += 50;
        } elseif (!empty($metaphone1) && !empty($metaphone2)) {
            // Partial metaphone match
            $metaphoneSim = $this->levenshteinSimilarity($metaphone1, $metaphone2);
            $score += ($metaphoneSim * 0.5);
        }
        
        return min(100, $score);
    }
    
    /**
     * Calculate token-based similarity (good for multi-word names)
     */
    private function tokenSimilarity($str1, $str2) {
        $tokens1 = preg_split('/\s+/', strtolower($str1), -1, PREG_SPLIT_NO_EMPTY);
        $tokens2 = preg_split('/\s+/', strtolower($str2), -1, PREG_SPLIT_NO_EMPTY);
        
        if (empty($tokens1) || empty($tokens2)) {
            return 0;
        }
        
        $matches = 0;
        $totalTokens = max(count($tokens1), count($tokens2));
        
        foreach ($tokens1 as $token1) {
            foreach ($tokens2 as $token2) {
                $sim = $this->levenshteinSimilarity($token1, $token2);
                if ($sim >= 80) { // 80% similar tokens count as match
                    $matches++;
                    break;
                }
            }
        }
        
        return ($matches / $totalTokens) * 100;
    }
    
    /**
     * Normalize text (remove accents, convert to lowercase, etc.)
     */
    private function normalizeText($text) {
        // Convert to lowercase
        $text = mb_strtolower($text, 'UTF-8');
        
        // Remove accents/diacritics
        $text = $this->removeAccents($text);
        
        // Remove extra spaces
        $text = preg_replace('/\s+/', ' ', trim($text));
        
        return $text;
    }
    
    /**
     * Remove accents and diacritical marks
     */
    private function removeAccents($text) {
        $unwanted_array = [
            'á'=>'a', 'à'=>'a', 'â'=>'a', 'ä'=>'a', 'ã'=>'a', 'å'=>'a', 'ą'=>'a',
            'é'=>'e', 'è'=>'e', 'ê'=>'e', 'ë'=>'e', 'ę'=>'e', 'ė'=>'e',
            'í'=>'i', 'ì'=>'i', 'î'=>'i', 'ï'=>'i', 'į'=>'i',
            'ó'=>'o', 'ò'=>'o', 'ô'=>'o', 'ö'=>'o', 'õ'=>'o', 'ø'=>'o', 'ō'=>'o',
            'ú'=>'u', 'ù'=>'u', 'û'=>'u', 'ü'=>'u', 'ū'=>'u', 'ų'=>'u',
            'ý'=>'y', 'ÿ'=>'y',
            'ñ'=>'n', 'ń'=>'n',
            'ç'=>'c', 'č'=>'c', 'ć'=>'c',
            'ş'=>'s', 'š'=>'s', 'ś'=>'s',
            'ž'=>'z', 'ź'=>'z', 'ż'=>'z',
            'Á'=>'A', 'À'=>'A', 'Â'=>'A', 'Ä'=>'A', 'Ã'=>'A', 'Å'=>'A', 'Ą'=>'A',
            'É'=>'E', 'È'=>'E', 'Ê'=>'E', 'Ë'=>'E', 'Ę'=>'E', 'Ė'=>'E',
            'Í'=>'I', 'Ì'=>'I', 'Î'=>'I', 'Ï'=>'I', 'Į'=>'I',
            'Ó'=>'O', 'Ò'=>'O', 'Ô'=>'O', 'Ö'=>'O', 'Õ'=>'O', 'Ø'=>'O', 'Ō'=>'O',
            'Ú'=>'U', 'Ù'=>'U', 'Û'=>'U', 'Ü'=>'U', 'Ū'=>'U', 'Ų'=>'U',
            'Ý'=>'Y', 'Ÿ'=>'Y',
            'Ñ'=>'N', 'Ń'=>'N',
            'Ç'=>'C', 'Č'=>'C', 'Ć'=>'C',
            'Ş'=>'S', 'Š'=>'S', 'Ś'=>'S',
            'Ž'=>'Z', 'Ź'=>'Z', 'Ż'=>'Z'
        ];
        
        return strtr($text, $unwanted_array);
    }
    
    /**
     * Parse name parts from full name string
     */
    private function parseNameParts($fullName) {
        $parts = preg_split('/\s+/', trim($fullName), -1, PREG_SPLIT_NO_EMPTY);
        
        $result = [
            'first' => '',
            'middle' => '',
            'last' => ''
        ];
        
        if (count($parts) == 1) {
            $result['first'] = $parts[0];
        } elseif (count($parts) == 2) {
            $result['first'] = $parts[0];
            $result['last'] = $parts[1];
        } else {
            $result['first'] = $parts[0];
            $result['last'] = $parts[count($parts) - 1];
            $result['middle'] = implode(' ', array_slice($parts, 1, -1));
        }
        
        return $result;
    }
    
    /**
     * Get confidence level description
     */
    private function getConfidenceLevel($score) {
        if ($score >= $this->config['exact_threshold']) {
            return 'Exact Match';
        } elseif ($score >= $this->config['high_threshold']) {
            return 'Very High';
        } elseif ($score >= $this->config['medium_threshold']) {
            return 'High';
        } elseif ($score >= $this->config['low_threshold']) {
            return 'Medium';
        } else {
            return 'Low';
        }
    }
    
    /**
     * Get configuration
     */
    public function getConfig() {
        return $this->config;
    }
    
    /**
     * Update configuration
     */
    public function updateConfig($key, $value) {
        if (isset($this->config[$key])) {
            $this->config[$key] = $value;
            return true;
        }
        return false;
    }
}

// Handle API Request
try {
    // Check if it's a POST request
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        // Get JSON input
        $input = json_decode(file_get_contents('php://input'), true);
        
        // Or get from POST data
        if (!$input) {
            $input = $_POST;
        }
        
        // Get database credentials (you can hardcode these or pass them)
        $dbHost = $input['db_host'] ?? DB_HOST;
        $dbName = $input['db_name'] ?? DB_NAME;
        $dbUser = $input['db_user'] ?? DB_USER;
        $dbPass = $input['db_pass'] ?? DB_PASS;
        
        // Create matcher instance
        $matcher = new FuzzyMatcher($dbHost, $dbName, $dbUser, $dbPass);
        
        // Get search parameters
        $searchTerm = $input['search_term'] ?? '';
        $searchType = $input['search_type'] ?? 'name';
        
        // Get options
        $options = [
            'include_fuzzy' => $input['include_fuzzy'] ?? true,
            'include_phonetic' => $input['include_phonetic'] ?? true,
            'min_score' => $input['min_score'] ?? 60,
            'max_results' => $input['max_results'] ?? 50
        ];
        
        // Perform search
        $result = $matcher->search($searchTerm, $searchType, $options);
        
        echo json_encode($result, JSON_PRETTY_PRINT);
        
    } elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
        // Simple GET request for testing
        if (isset($_GET['search'])) {
            $matcher = new FuzzyMatcher(DB_HOST, DB_NAME, DB_USER, DB_PASS);
            
            $searchType = $_GET['type'] ?? 'name';
            $minScore = $_GET['min_score'] ?? 60;
            $maxResults = $_GET['max_results'] ?? 20;
            
            $options = [
                'min_score' => (int)$minScore,
                'max_results' => (int)$maxResults
            ];
            
            $result = $matcher->search($_GET['search'], $searchType, $options);
            echo json_encode($result, JSON_PRETTY_PRINT);
        } else {
            // Return API documentation
            echo json_encode([
                'api' => 'PFA Fuzzy Matching Engine',
                'version' => '1.0',
                'endpoints' => [
                    'POST /' => 'Main search endpoint',
                    'GET /?search=term&type=name' => 'Simple GET search'
                ],
                'search_types' => [
                    'name' => 'Search by first name or surname',
                    'full_name' => 'Search by full name (multiple parts)',
                    'nationality' => 'Search by nationality',
                    'all' => 'Search across all fields'
                ],
                'example' => [
                    'url' => '?search=John&type=name&min_score=70&max_results=10',
                    'post_data' => [
                        'search_term' => 'John Smith',
                        'search_type' => 'full_name',
                        'min_score' => 70,
                        'max_results' => 20
                    ]
                ]
            ], JSON_PRETTY_PRINT);
        }
    }
    
} catch (Exception $e) {
    http_response_code(500);
    echo json_encode([
        'success' => false,
        'error' => $e->getMessage()
    ]);
}