<?php
namespace Avision;

/**
 * Analyseur NLP pour le Mode Gardien
 * 
 * Analyse sémantique des avis pour extraire le contexte,
 * les entités et le sentiment sans intervention humaine.
 * 
 * Inclut la détection de contenu suspect, spam et injurieux.
 */
class Guardian_NLP_Analyzer {
    
    /**
     * Mots injurieux à détecter (blocage automatique)
     */
    private $profanity_words = [
        'fr' => [
            'merde', 'putain', 'connard', 'connasse', 'enculé', 'salaud', 'salope',
            'bâtard', 'con', 'conne', 'débile', 'crétin', 'idiot', 'imbécile',
            'nul à chier', 'pourri', 'ordure', 'enfoiré', 'abruti', 'taré',
            'fils de pute', 'pute', 'bordel', 'foutre', 'niquer', 'baiser'
        ],
        'en' => [
            'fuck', 'shit', 'damn', 'ass', 'asshole', 'bastard', 'bitch',
            'crap', 'idiot', 'moron', 'stupid', 'dumb', 'retard', 'loser',
            'suck', 'bullshit', 'cunt', 'dick', 'piss', 'screw you'
        ]
    ];
    
    /**
     * Indicateurs de spam/avis suspect
     */
    private $spam_indicators = [
        'fr' => [
            'cliquez ici', 'visitez notre site', 'www.', 'http', 'promo', 
            'gratuit', 'gagnez', 'bitcoin', 'crypto', 'arnaque', 
            'faux avis', 'concurrent', 'jamais été', 'jamais client'
        ],
        'en' => [
            'click here', 'visit our site', 'www.', 'http', 'promo',
            'free', 'win', 'bitcoin', 'crypto', 'scam',
            'fake review', 'competitor', 'never been', 'never customer'
        ]
    ];
    
    /**
     * Dictionnaire de mots-clés par catégorie
     */
    private $keywords = [
        'service' => [
            'fr' => ['service', 'accueil', 'personnel', 'équipe', 'conseiller', 'vendeur', 'réception'],
            'en' => ['service', 'staff', 'team', 'employee', 'reception', 'welcome', 'greeting']
        ],
        'quality' => [
            'fr' => ['qualité', 'produit', 'travail', 'prestation', 'résultat', 'finition'],
            'en' => ['quality', 'product', 'work', 'result', 'finish', 'craftsmanship']
        ],
        'price' => [
            'fr' => ['prix', 'tarif', 'coût', 'cher', 'abordable', 'rapport qualité-prix'],
            'en' => ['price', 'cost', 'expensive', 'affordable', 'value', 'rate']
        ],
        'speed' => [
            'fr' => ['rapide', 'délai', 'attente', 'temps', 'rapidité', 'ponctuel'],
            'en' => ['fast', 'quick', 'delay', 'wait', 'time', 'speed', 'punctual']
        ],
        'cleanliness' => [
            'fr' => ['propre', 'propreté', 'hygiène', 'rangé', 'soigné'],
            'en' => ['clean', 'cleanliness', 'hygiene', 'tidy', 'neat']
        ],
        'location' => [
            'fr' => ['emplacement', 'lieu', 'accès', 'parking', 'localisation'],
            'en' => ['location', 'place', 'access', 'parking', 'position']
        ],
        'expertise' => [
            'fr' => ['compétent', 'professionnel', 'expert', 'qualifié', 'expérience'],
            'en' => ['competent', 'professional', 'expert', 'qualified', 'experienced']
        ]
    ];
    
    /**
     * Mots de sentiment positif/négatif
     */
    private $sentiment_words = [
        'positive' => [
            'fr' => ['excellent', 'parfait', 'super', 'génial', 'top', 'recommande', 'satisfait', 'content', 'merci', 'bravo'],
            'en' => ['excellent', 'perfect', 'great', 'amazing', 'awesome', 'recommend', 'satisfied', 'happy', 'thanks', 'wonderful']
        ],
        'negative' => [
            'fr' => ['mauvais', 'nul', 'déçu', 'décevant', 'problème', 'erreur', 'jamais', 'éviter', 'catastrophe'],
            'en' => ['bad', 'terrible', 'disappointed', 'disappointing', 'problem', 'error', 'never', 'avoid', 'awful']
        ]
    ];
    
    /**
     * Analyse complète d'un avis
     * 
     * @param string $text Texte de l'avis
     * @param string $language Langue de l'avis
     * @return array Contexte extrait
     */
    public function analyze($text, $language = 'fr') {
        $text_lower = mb_strtolower($text);
        
        // Détection de sécurité
        $is_profane = $this->detect_profanity($text_lower, $language);
        $is_spam = $this->detect_spam($text_lower, $language);
        $is_empty = empty(trim($text)) || strlen(trim($text)) < 3;
        
        return [
            'categories' => $this->extract_categories($text_lower, $language),
            'entities' => $this->extract_entities($text),
            'sentiment' => $this->analyze_sentiment($text_lower, $language),
            'keywords' => $this->extract_key_phrases($text_lower, $language),
            'has_specific_mention' => $this->has_specific_mention($text),
            'is_detailed' => strlen($text) > 50,
            'is_empty' => $is_empty,
            'is_profane' => $is_profane,
            'is_spam' => $is_spam,
            'requires_human_review' => $is_profane || $is_spam,
            'profanity_details' => $is_profane ? $this->get_profanity_details($text_lower, $language) : null,
            'spam_details' => $is_spam ? $this->get_spam_details($text_lower, $language) : null
        ];
    }
    
    /**
     * Détecte si le texte contient du langage injurieux
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return bool True si contenu injurieux détecté
     */
    public function detect_profanity($text, $language = 'fr') {
        $words = $this->profanity_words[$language] ?? $this->profanity_words['fr'];
        
        foreach ($words as $word) {
            if (strpos($text, $word) !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * Récupère les détails des mots injurieux détectés
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return array Détails des mots trouvés
     */
    private function get_profanity_details($text, $language) {
        $words = $this->profanity_words[$language] ?? $this->profanity_words['fr'];
        $found = [];
        
        foreach ($words as $word) {
            if (strpos($text, $word) !== false) {
                $found[] = $word;
            }
        }
        
        return [
            'words_found' => $found,
            'count' => count($found),
            'severity' => count($found) > 2 ? 'high' : 'medium'
        ];
    }
    
    /**
     * Détecte si l'avis semble être du spam
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return bool True si spam détecté
     */
    public function detect_spam($text, $language = 'fr') {
        $indicators = $this->spam_indicators[$language] ?? $this->spam_indicators['fr'];
        $spam_count = 0;
        
        foreach ($indicators as $indicator) {
            if (strpos($text, $indicator) !== false) {
                $spam_count++;
            }
        }
        
        // Autres indicateurs de spam
        // - Trop de majuscules
        $uppercase_ratio = preg_match_all('/[A-Z]/', $text) / max(strlen($text), 1);
        if ($uppercase_ratio > 0.5) {
            $spam_count++;
        }
        
        // - Répétition excessive de caractères
        if (preg_match('/(.)\1{4,}/', $text)) {
            $spam_count++;
        }
        
        // - Présence d'URLs
        if (preg_match('/https?:\/\//', $text)) {
            $spam_count++;
        }
        
        // - Adresses email dans le texte
        if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $text)) {
            $spam_count++;
        }
        
        return $spam_count >= 2;
    }
    
    /**
     * Récupère les détails du spam détecté
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return array Détails du spam
     */
    private function get_spam_details($text, $language) {
        $indicators = $this->spam_indicators[$language] ?? $this->spam_indicators['fr'];
        $found = [];
        $reasons = [];
        
        foreach ($indicators as $indicator) {
            if (strpos($text, $indicator) !== false) {
                $found[] = $indicator;
            }
        }
        
        if (!empty($found)) {
            $reasons[] = 'Mots-clés suspects détectés';
        }
        
        if (preg_match('/https?:\/\//', $text)) {
            $reasons[] = 'URL détectée';
        }
        
        if (preg_match('/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/', $text)) {
            $reasons[] = 'Email détecté';
        }
        
        $uppercase_ratio = preg_match_all('/[A-Z]/', $text) / max(strlen($text), 1);
        if ($uppercase_ratio > 0.5) {
            $reasons[] = 'Trop de majuscules';
        }
        
        if (preg_match('/(.)\1{4,}/', $text)) {
            $reasons[] = 'Caractères répétitifs';
        }
        
        return [
            'indicators_found' => $found,
            'reasons' => $reasons,
            'spam_type' => !empty($found) ? 'promotional' : 'suspicious'
        ];
    }
    
    /**
     * Extrait les catégories mentionnées dans l'avis
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return array Catégories détectées avec scores
     */
    private function extract_categories($text, $language) {
        $detected = [];
        
        foreach ($this->keywords as $category => $translations) {
            $words = $translations[$language] ?? $translations['fr'];
            $count = 0;
            
            foreach ($words as $keyword) {
                if (strpos($text, $keyword) !== false) {
                    $count++;
                }
            }
            
            if ($count > 0) {
                $detected[$category] = $count;
            }
        }
        
        // Trier par pertinence
        arsort($detected);
        
        return $detected;
    }
    
    /**
     * Extrait les entités nommées (noms de personnes, services spécifiques)
     * 
     * @param string $text Texte original
     * @return array Entités détectées
     */
    private function extract_entities($text) {
        $entities = [];
        
        // Détection de noms propres (mots commençant par une majuscule)
        preg_match_all('/\b[A-ZÀ-ÿ][a-zà-ÿ]+\b/', $text, $matches);
        
        if (!empty($matches[0])) {
            $entities['names'] = array_unique($matches[0]);
        }
        
        // Détection de services spécifiques entre guillemets
        preg_match_all('/"([^"]+)"/', $text, $quotes);
        if (!empty($quotes[1])) {
            $entities['services'] = $quotes[1];
        }
        
        return $entities;
    }
    
    /**
     * Analyse le sentiment général de l'avis
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return array Score de sentiment
     */
    private function analyze_sentiment($text, $language) {
        $positive_count = 0;
        $negative_count = 0;
        
        // Compter les mots positifs
        foreach ($this->sentiment_words['positive'][$language] as $word) {
            $positive_count += substr_count($text, $word);
        }
        
        // Compter les mots négatifs
        foreach ($this->sentiment_words['negative'][$language] as $word) {
            $negative_count += substr_count($text, $word);
        }
        
        $total = $positive_count + $negative_count;
        
        if ($total == 0) {
            return ['score' => 0, 'type' => 'neutral'];
        }
        
        $score = ($positive_count - $negative_count) / $total;
        
        if ($score > 0.3) {
            $type = 'positive';
        } elseif ($score < -0.3) {
            $type = 'negative';
        } else {
            $type = 'neutral';
        }
        
        return [
            'score' => round($score, 2),
            'type' => $type,
            'positive_words' => $positive_count,
            'negative_words' => $negative_count
        ];
    }
    
    /**
     * Extrait les phrases clés de l'avis
     * 
     * @param string $text Texte en minuscules
     * @param string $language Langue
     * @return array Phrases importantes
     */
    private function extract_key_phrases($text, $language) {
        $phrases = [];
        
        // Séparer en phrases
        $sentences = preg_split('/[.!?]+/', $text);
        
        foreach ($sentences as $sentence) {
            $sentence = trim($sentence);
            if (strlen($sentence) < 10) continue;
            
            // Vérifier si la phrase contient des mots-clés importants
            foreach ($this->keywords as $category => $translations) {
                $words = $translations[$language] ?? $translations['fr'];
                
                foreach ($words as $keyword) {
                    if (strpos($sentence, $keyword) !== false) {
                        $phrases[] = [
                            'text' => $sentence,
                            'category' => $category
                        ];
                        break 2;
                    }
                }
            }
        }
        
        return array_slice($phrases, 0, 3); // Max 3 phrases clés
    }
    
    /**
     * Vérifie si l'avis mentionne quelque chose de spécifique
     * 
     * @param string $text Texte original
     * @return bool
     */
    private function has_specific_mention($text) {
        // Un avis est considéré comme spécifique s'il contient:
        // - Des noms propres
        // - Des guillemets
        // - Des chiffres
        // - Plus de 100 caractères
        
        return preg_match('/[A-ZÀ-Ÿ][a-zà-ÿ]+/', $text) ||
               strpos($text, '"') !== false ||
               preg_match('/\d+/', $text) ||
               strlen($text) > 100;
    }
    
    /**
     * Détecte automatiquement la langue d'un texte
     * 
     * @param string $text Texte à analyser
     * @return string Code langue (fr, en, es)
     */
    public function detect_language($text) {
        $text_lower = mb_strtolower($text);
        
        // Mots communs par langue
        $language_indicators = [
            'fr' => ['le', 'la', 'les', 'de', 'des', 'un', 'une', 'et', 'est', 'très', 'pour', 'avec'],
            'en' => ['the', 'and', 'is', 'was', 'very', 'for', 'with', 'this', 'that', 'have'],
            'es' => ['el', 'la', 'los', 'las', 'de', 'del', 'un', 'una', 'y', 'es', 'muy', 'para']
        ];
        
        $scores = [];
        
        foreach ($language_indicators as $lang => $words) {
            $count = 0;
            foreach ($words as $word) {
                $count += substr_count($text_lower, ' ' . $word . ' ');
            }
            $scores[$lang] = $count;
        }
        
        arsort($scores);
        
        return key($scores) ?: 'fr';
    }
}
