File size: 34,073 Bytes
8c13f2b
5ad533d
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
7b51008
8c13f2b
5ad533d
 
 
 
 
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e558da9
5ad533d
 
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
 
7b51008
 
5ad533d
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
939382b
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939382b
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939382b
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
 
5ad533d
7b51008
5ad533d
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
 
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
 
5ad533d
 
7b51008
 
5ad533d
 
7b51008
 
5ad533d
 
 
 
 
 
 
 
7b51008
 
5ad533d
 
7b51008
5ad533d
939382b
5ad533d
 
 
 
 
7b51008
5ad533d
7b51008
 
 
 
 
5ad533d
7b51008
5ad533d
 
7b51008
 
 
 
 
5ad533d
7b51008
5ad533d
 
7b51008
 
 
 
5ad533d
 
7b51008
 
 
 
5ad533d
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
 
 
5ad533d
 
 
7b51008
5ad533d
7b51008
 
5ad533d
7b51008
5ad533d
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
 
 
7b51008
5ad533d
7b51008
5ad533d
7b51008
5ad533d
 
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
 
 
7b51008
5ad533d
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
 
7b51008
5ad533d
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
 
7b51008
5ad533d
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
 
 
 
 
 
 
7b51008
5ad533d
 
7b51008
5ad533d
7b51008
 
5ad533d
7b51008
 
 
 
 
5ad533d
 
 
7b51008
5ad533d
 
7b51008
5ad533d
 
7b51008
5ad533d
7b51008
5ad533d
 
 
 
7b51008
5ad533d
7b51008
5ad533d
7b51008
5ad533d
 
 
 
 
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8c13f2b
7b51008
5ad533d
 
 
 
7b51008
5ad533d
7b51008
5ad533d
 
7b51008
 
 
 
 
 
5ad533d
7b51008
 
 
5ad533d
7b51008
5ad533d
 
 
 
 
7b51008
5ad533d
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
from typing import Any
from smolagents.tools import Tool
import requests
from datetime import datetime, timedelta
import json
import os
from dotenv import load_dotenv
import re
import anthropic

class CountryInfoTool(Tool):
    name = "country_info"
    description = "Retrieves important contextual information about a country in real-time: security, current events, national holidays, political climate, travel advice."
    inputs = {
        'country': {'type': 'string', 'description': 'Country name in French or English (e.g., "France", "United States", "Japan")'},
        'info_type': {'type': 'string', 'description': 'Type of information requested: "all" (recommended), "security", "events", "holidays", "travel", "politics"', 'nullable': True}
    }
    output_type = "string"

    def __init__(self):
        super().__init__()
        load_dotenv()
        
        # Initialiser le client Claude (Anthropic)
        self.claude_client = anthropic.Anthropic(api_key=os.getenv('ANTROPIC_KEY'))
        
        # Mapping étendu des pays français vers anglais pour les APIs
        self.country_mapping = {
            # Europe
            'france': 'France', 'allemagne': 'Germany', 'italie': 'Italy', 'espagne': 'Spain',
            'royaume-uni': 'United Kingdom', 'angleterre': 'United Kingdom', 'écosse': 'United Kingdom',
            'pays-bas': 'Netherlands', 'hollande': 'Netherlands', 'belgique': 'Belgium', 
            'suisse': 'Switzerland', 'autriche': 'Austria', 'portugal': 'Portugal',
            'suède': 'Sweden', 'norvège': 'Norway', 'danemark': 'Denmark', 'finlande': 'Finland',
            'pologne': 'Poland', 'république tchèque': 'Czech Republic', 'tchéquie': 'Czech Republic',
            'hongrie': 'Hungary', 'roumanie': 'Romania', 'bulgarie': 'Bulgaria',
            'grèce': 'Greece', 'croatie': 'Croatia', 'slovénie': 'Slovenia', 'slovaquie': 'Slovakia',
            'estonie': 'Estonia', 'lettonie': 'Latvia', 'lituanie': 'Lithuania',
            'irlande': 'Ireland', 'islande': 'Iceland', 'malte': 'Malta', 'chypre': 'Cyprus',
            'serbie': 'Serbia', 'bosnie': 'Bosnia and Herzegovina', 'monténégro': 'Montenegro',
            'macédoine': 'North Macedonia', 'albanie': 'Albania', 'moldavie': 'Moldova',
            'ukraine': 'Ukraine', 'biélorussie': 'Belarus', 'russie': 'Russia',
            
            # Amériques
            'états-unis': 'United States', 'usa': 'United States', 'amérique': 'United States',
            'canada': 'Canada', 'mexique': 'Mexico',
            'brésil': 'Brazil', 'argentine': 'Argentina', 'chili': 'Chile', 'pérou': 'Peru',
            'colombie': 'Colombia', 'venezuela': 'Venezuela', 'équateur': 'Ecuador',
            'bolivie': 'Bolivia', 'paraguay': 'Paraguay', 'uruguay': 'Uruguay',
            'guatemala': 'Guatemala', 'costa rica': 'Costa Rica', 'panama': 'Panama',
            'cuba': 'Cuba', 'jamaïque': 'Jamaica', 'haïti': 'Haiti', 'république dominicaine': 'Dominican Republic',
            
            # Asie
            'chine': 'China', 'japon': 'Japan', 'corée du sud': 'South Korea', 'corée du nord': 'North Korea',
            'inde': 'India', 'pakistan': 'Pakistan', 'bangladesh': 'Bangladesh', 'sri lanka': 'Sri Lanka',
            'thaïlande': 'Thailand', 'vietnam': 'Vietnam', 'cambodge': 'Cambodia', 'laos': 'Laos',
            'myanmar': 'Myanmar', 'birmanie': 'Myanmar', 'malaisie': 'Malaysia', 'singapour': 'Singapore',
            'indonésie': 'Indonesia', 'philippines': 'Philippines', 'brunei': 'Brunei',
            'mongolie': 'Mongolia', 'kazakhstan': 'Kazakhstan', 'ouzbékistan': 'Uzbekistan',
            'kirghizistan': 'Kyrgyzstan', 'tadjikistan': 'Tajikistan', 'turkménistan': 'Turkmenistan',
            'afghanistan': 'Afghanistan', 'iran': 'Iran', 'irak': 'Iraq', 'syrie': 'Syria',
            'turquie': 'Turkey', 'israël': 'Israel', 'palestine': 'Palestine', 'liban': 'Lebanon',
            'jordanie': 'Jordan', 'arabie saoudite': 'Saudi Arabia', 'émirats arabes unis': 'United Arab Emirates',
            'qatar': 'Qatar', 'koweït': 'Kuwait', 'bahreïn': 'Bahrain', 'oman': 'Oman', 'yémen': 'Yemen',
            
            # Afrique
            'maroc': 'Morocco', 'algérie': 'Algeria', 'tunisie': 'Tunisia', 'libye': 'Libya', 'égypte': 'Egypt',
            'soudan': 'Sudan', 'éthiopie': 'Ethiopia', 'kenya': 'Kenya', 'tanzanie': 'Tanzania',
            'ouganda': 'Uganda', 'rwanda': 'Rwanda', 'burundi': 'Burundi', 'congo': 'Democratic Republic of the Congo',
            'république démocratique du congo': 'Democratic Republic of the Congo', 'rdc': 'Democratic Republic of the Congo',
            'république du congo': 'Republic of the Congo', 'cameroun': 'Cameroon', 'nigeria': 'Nigeria',
            'ghana': 'Ghana', 'côte d\'ivoire': 'Ivory Coast', 'sénégal': 'Senegal', 'mali': 'Mali',
            'burkina faso': 'Burkina Faso', 'niger': 'Niger', 'tchad': 'Chad', 'centrafrique': 'Central African Republic',
            'gabon': 'Gabon', 'guinée équatoriale': 'Equatorial Guinea', 'sao tomé': 'Sao Tome and Principe',
            'cap-vert': 'Cape Verde', 'guinée-bissau': 'Guinea-Bissau', 'guinée': 'Guinea',
            'sierra leone': 'Sierra Leone', 'liberia': 'Liberia', 'togo': 'Togo', 'bénin': 'Benin',
            'mauritanie': 'Mauritania', 'gambie': 'Gambia', 'afrique du sud': 'South Africa',
            'namibie': 'Namibia', 'botswana': 'Botswana', 'zimbabwe': 'Zimbabwe', 'zambie': 'Zambia',
            'malawi': 'Malawi', 'mozambique': 'Mozambique', 'madagascar': 'Madagascar', 'maurice': 'Mauritius',
            'seychelles': 'Seychelles', 'comores': 'Comoros', 'djibouti': 'Djibouti', 'érythrée': 'Eritrea',
            'somalie': 'Somalia', 'lesotho': 'Lesotho', 'eswatini': 'Eswatini', 'swaziland': 'Eswatini',
            
            # Océanie
            'australie': 'Australia', 'nouvelle-zélande': 'New Zealand', 'fidji': 'Fiji',
            'papouasie-nouvelle-guinée': 'Papua New Guinea', 'vanuatu': 'Vanuatu', 'samoa': 'Samoa',
            'tonga': 'Tonga', 'îles salomon': 'Solomon Islands', 'micronésie': 'Micronesia',
            'palau': 'Palau', 'nauru': 'Nauru', 'kiribati': 'Kiribati', 'tuvalu': 'Tuvalu'
        }
        
        # Codes ISO pour certaines APIs
        self.country_codes = {
            'France': 'FR', 'United States': 'US', 'United Kingdom': 'GB',
            'Germany': 'DE', 'Italy': 'IT', 'Spain': 'ES', 'Japan': 'JP',
            'China': 'CN', 'India': 'IN', 'Brazil': 'BR', 'Canada': 'CA',
            'Australia': 'AU', 'Russia': 'RU', 'Mexico': 'MX', 'South Korea': 'KR',
            'Netherlands': 'NL', 'Belgium': 'BE', 'Switzerland': 'CH',
            'Sweden': 'SE', 'Norway': 'NO', 'Denmark': 'DK', 'Turkey': 'TR',
            'Egypt': 'EG', 'Thailand': 'TH', 'Iran': 'IR'
        }

    def forward(self, country: str, info_type: str = "all") -> str:
        try:
            # Normaliser le nom du pays
            country_normalized = self._normalize_country_name(country)
            
            if not country_normalized:
                return f"❌ Country not recognized: '{country}'. Try with the full name (e.g., 'France', 'United States', 'United Kingdom')"
            
            # Collecter les informations selon le type demandé
            info_sections = []
            
            if info_type in ["all", "security"]:
                security_info = self._get_security_info(country_normalized)
                if security_info:
                    info_sections.append(security_info)
            
            if info_type in ["all", "events"]:
                events_info = self._get_current_events_info(country_normalized)
                if events_info:
                    info_sections.append(events_info)
            
            if info_type in ["all", "holidays"]:
                holidays_info = self._get_holidays_info(country_normalized)
                if holidays_info:
                    info_sections.append(holidays_info)
            
            if info_type in ["all", "travel"]:
                travel_info = self._get_travel_info(country_normalized)
                if travel_info:
                    info_sections.append(travel_info)
            
            if info_type in ["all", "politics"]:
                politics_info = self._get_political_info(country_normalized)
                if politics_info:
                    info_sections.append(politics_info)
            
            if not info_sections:
                return f"❌ No information available for {country_normalized} currently."
            
            # Assembler le rapport final
            result = f"🌍 **Contextual Information for {country_normalized}**\n"
            result += f"*Updated: {datetime.now().strftime('%m/%d/%Y %H:%M')}*\n\n"
            result += "\n\n".join(info_sections)
            
            # Ajouter une recommandation finale intelligente si Claude est disponible et qu'on demande toutes les infos
            if info_type == "all" and self.claude_client:
                final_recommendation = self._get_llm_final_recommendation(country_normalized, "\n\n".join(info_sections))
                if final_recommendation:
                    result += f"\n\n{final_recommendation}"
            
            return result
            
        except Exception as e:
            return f"❌ Error retrieving information: {str(e)}"

    def _normalize_country_name(self, country: str):
        """Normalise le nom du pays"""
        country_lower = country.lower().strip()
        
        # Vérifier dans le mapping français -> anglais
        if country_lower in self.country_mapping:
            return self.country_mapping[country_lower]
        
        # Vérifier si c'est déjà un nom anglais valide
        for french, english in self.country_mapping.items():
            if country_lower == english.lower():
                return english
        
        # Essayer une correspondance partielle
        for french, english in self.country_mapping.items():
            if country_lower in french or french in country_lower:
                return english
        
        # Si pas trouvé dans le mapping, essayer de valider via l'API REST Countries
        validated_country = self._validate_country_via_api(country)
        if validated_country:
            return validated_country
        
        return None

    def _validate_country_via_api(self, country: str):
        """Valide et normalise le nom du pays via l'API REST Countries"""
        try:
            # Essayer d'abord avec le nom exact
            url = f"https://restcountries.com/v3.1/name/{country}"
            response = requests.get(url, timeout=5)
            
            if response.status_code == 200:
                data = response.json()
                if data:
                    # Retourner le nom officiel en anglais
                    return data[0].get('name', {}).get('common', country.title())
            
            # Si échec, essayer avec une recherche partielle
            url = f"https://restcountries.com/v3.1/name/{country}?fullText=false"
            response = requests.get(url, timeout=5)
            
            if response.status_code == 200:
                data = response.json()
                if data:
                    # Prendre le premier résultat
                    return data[0].get('name', {}).get('common', country.title())
            
            return None
            
        except Exception:
            # En cas d'erreur, retourner le nom avec la première lettre en majuscule
            return country.title() if len(country) > 2 else None

    def _get_country_code_from_api(self, country: str):
        """Récupère le code ISO du pays via l'API REST Countries"""
        try:
            url = f"https://restcountries.com/v3.1/name/{country}"
            response = requests.get(url, timeout=5)
            
            if response.status_code == 200:
                data = response.json()
                if data:
                    # Retourner le code ISO alpha-2
                    return data[0].get('cca2', '')
            
            return None
            
        except Exception:
            return None

    def _get_security_info(self, country: str) -> str:
        """Récupère les informations de sécurité avec recherche exhaustive"""
        try:
            # Vérifier d'abord si c'est un pays à risque connu
            risk_level = self._check_known_risk_countries(country)
            
            # Recherches multiples avec différents mots-clés
            all_news_data = []
            
            # Recherche 1: Sécurité générale
            security_keywords = f"{country} travel advisory security warning conflict war"
            news_data1 = self._search_security_news(security_keywords)
            all_news_data.extend(news_data1)
            
            # Recherche 2: Conflits spécifiques
            conflict_keywords = f"{country} war conflict violence terrorism attack bombing"
            news_data2 = self._search_security_news(conflict_keywords)
            all_news_data.extend(news_data2)
            
            # Recherche 3: Instabilité politique
            political_keywords = f"{country} coup government crisis instability sanctions"
            news_data3 = self._search_security_news(political_keywords)
            all_news_data.extend(news_data3)
            
            # Recherche 4: Alertes de voyage
            travel_keywords = f"{country} 'travel ban' 'do not travel' 'avoid travel' embassy"
            news_data4 = self._search_security_news(travel_keywords)
            all_news_data.extend(news_data4)
            
            # Supprimer les doublons
            unique_news = []
            seen_titles = set()
            for article in all_news_data:
                title = article.get('title', '')
                if title and title not in seen_titles:
                    unique_news.append(article)
                    seen_titles.add(title)
            
            # Analyser les résultats pour déterminer le niveau de sécurité
            security_level, description, recommendation = self._analyze_security_data(country, unique_news, risk_level)
            
            result = f"🛡️ **Security and Travel Advice**\n"
            result += f"{security_level} **Level determined by real-time analysis**\n"
            result += f"📋 {description}\n"
            result += f"🎯 **Recommendation: {recommendation}**"
            
            return result
            
        except Exception as e:
            return f"🛡️ **Security**: Error during retrieval - {str(e)}"

    def _check_known_risk_countries(self, country: str) -> str:
        """Vérifie si le pays est dans la liste des pays à risque connus"""
        
        # Pays à très haut risque (guerre active, conflit majeur)
        high_risk_countries = [
            'Ukraine', 'Afghanistan', 'Syria', 'Yemen', 'Somalia', 'South Sudan',
            'Central African Republic', 'Mali', 'Burkina Faso', 'Niger',
            'Democratic Republic of the Congo', 'Myanmar', 'Palestine', 'Gaza',
            'West Bank', 'Iraq', 'Libya', 'Sudan'
        ]
        
        # Pays à risque modéré (instabilité, tensions)
        moderate_risk_countries = [
            'Iran', 'North Korea', 'Venezuela', 'Belarus', 'Ethiopia',
            'Chad', 'Cameroon', 'Nigeria', 'Pakistan', 'Bangladesh',
            'Haiti', 'Lebanon', 'Turkey', 'Egypt', 'Algeria'
        ]
        
        # Pays avec tensions spécifiques
        tension_countries = [
            'Russia', 'China', 'Israel', 'India', 'Kashmir', 'Taiwan',
            'Hong Kong', 'Thailand', 'Philippines', 'Colombia'
        ]
        
        country_lower = country.lower()
        
        for risk_country in high_risk_countries:
            if risk_country.lower() in country_lower or country_lower in risk_country.lower():
                return "HIGH_RISK"
        
        for risk_country in moderate_risk_countries:
            if risk_country.lower() in country_lower or country_lower in risk_country.lower():
                return "MODERATE_RISK"
                
        for risk_country in tension_countries:
            if risk_country.lower() in country_lower or country_lower in risk_country.lower():
                return "TENSION"
        
        return "UNKNOWN"

    def _search_security_news(self, keywords: str) -> list:
        """Recherche d'actualités de sécurité avec période étendue"""
        try:
            # Utiliser NewsAPI si disponible
            api_key = os.getenv('NEWSAPI_KEY')
            if api_key:
                url = "https://newsapi.org/v2/everything"
                params = {
                    'q': keywords,
                    'sortBy': 'publishedAt',
                    'pageSize': 20,  # Plus d'articles
                    'language': 'en',
                    'from': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),  # 30 jours au lieu de 7
                    'apiKey': api_key
                }
                
                response = requests.get(url, params=params, timeout=10)
                if response.status_code == 200:
                    data = response.json()
                    articles = data.get('articles', [])
                    
                    # Filtrer les articles pertinents
                    relevant_articles = []
                    for article in articles:
                        title = article.get('title', '').lower()
                        description = article.get('description', '').lower()
                        
                        # Mots-clés critiques pour filtrer
                        critical_keywords = ['war', 'conflict', 'attack', 'bombing', 'terrorism', 
                                           'violence', 'crisis', 'coup', 'sanctions', 'advisory',
                                           'warning', 'danger', 'risk', 'threat', 'security']
                        
                        if any(keyword in title or keyword in description for keyword in critical_keywords):
                            relevant_articles.append(article)
                    
                    return relevant_articles
            
            # Fallback: recherche via une API publique alternative
            return self._search_alternative_news(keywords)
            
        except Exception:
            return []

    def _search_alternative_news(self, keywords: str) -> list:
        """Recherche alternative sans API key"""
        try:
            # Utiliser une API publique comme Guardian ou BBC
            # Pour l'exemple, on simule une recherche basique
            dangerous_keywords = ['war', 'conflict', 'terrorism', 'violence', 'crisis', 'coup', 'sanctions']
            warning_keywords = ['protest', 'unrest', 'advisory', 'caution', 'alert']
            
            # Simulation basée sur les mots-clés (à remplacer par vraie API)
            if any(word in keywords.lower() for word in dangerous_keywords):
                return [{'title': f'Security concerns in {keywords.split()[0]}', 'description': 'Recent security developments'}]
            elif any(word in keywords.lower() for word in warning_keywords):
                return [{'title': f'Travel advisory for {keywords.split()[0]}', 'description': 'Caution advised'}]
            
            return []
            
        except Exception:
            return []

    def _analyze_security_data(self, country: str, news_data: list, risk_level: str = "UNKNOWN") -> tuple:
        """Analyse les données de sécurité avec Claude uniquement"""
        try:
            if not self.claude_client:
                return ("⚪", 
                       "Claude not available", 
                       "❓ Anthropic API key required for security analysis")
            
            # Préparer le contenu des actualités pour l'analyse
            news_content = ""
            for i, article in enumerate(news_data[:10], 1):  # Limiter à 10 articles
                title = article.get('title', '')
                description = article.get('description', '')
                if title or description:
                    news_content += f"{i}. {title}\n{description}\n\n"
            
            # Si pas d'actualités mais pays à haut risque connu, forcer l'analyse
            if not news_content.strip():
                if risk_level == "HIGH_RISK":
                    return ("🔴", 
                           f"Very high risk country - active conflict or war",
                           "🚫 CHANGE DESTINATION - Active conflict zone")
                elif risk_level == "MODERATE_RISK":
                    return ("🟡", 
                           f"Moderate risk country - political instability",
                           "⚠️ Travel possible with enhanced precautions")
                else:
                    return ("🟢", 
                           f"No recent security news found",
                           "✅ Destination considered safe")
            
            # Utiliser Claude pour analyser
            analysis = self._llm_security_analysis(country, news_content, risk_level)
            
            if analysis:
                return analysis
            else:
                return ("⚪", 
                       "Claude analysis error", 
                       "❓ Unable to analyze security currently")
                       
        except Exception:
            return ("⚪", "Analysis impossible", "❓ Consult official sources")

    def _llm_security_analysis(self, country: str, news_content: str, risk_level: str = "UNKNOWN"):
        """Utilise Claude pour analyser la sécurité du pays"""
        try:
            if not self.claude_client:
                return None
                
            prompt = f"""Analyze the following recent news about {country} and determine the security level for a traveler:

KNOWN RISK LEVEL: {risk_level}
- HIGH_RISK = Country in active war or major conflict
- MODERATE_RISK = Country with significant political instability  
- TENSION = Country with geopolitical tensions
- UNKNOWN = No special classification

RECENT NEWS:
{news_content}

CRITICAL INSTRUCTIONS:
1. If RISK LEVEL = HIGH_RISK, you MUST recommend CHANGE_DESTINATION unless clear evidence of improvement
2. For Ukraine, Palestine, Afghanistan, Syria, Yemen: ALWAYS RED/CHANGE_DESTINATION
3. Analyze risk level for a civilian tourist/traveler
4. Be VERY STRICT - traveler safety is priority

Respond ONLY in the following JSON format:

{{
    "level": "RED|YELLOW|GREEN",
    "description": "Short situation description (max 100 characters)",
    "recommendation": "CHANGE_DESTINATION|ENHANCED_PRECAUTIONS|SAFE_DESTINATION",
    "justification": "Explanation of your decision (max 200 characters)"
}}

STRICT Criteria:
- RED/CHANGE_DESTINATION: active war, armed conflict, active terrorism, coup, widespread violence, combat zones
- YELLOW/ENHANCED_PRECAUTIONS: violent protests, very high crime, political instability, ethnic tensions
- GREEN/SAFE_DESTINATION: no major risks for civilians

ABSOLUTE PRIORITY: Protect travelers - when in doubt, choose the strictest security level."""

            response = self.claude_client.messages.create(
                model="claude-3-opus-20240229",
                max_tokens=300,
                temperature=0.1,
                system="Vous êtes un expert en sécurité des voyages. Analysez objectivement les risques.",
                messages=[
                    {"role": "user", "content": prompt}
                ]
            )
            
            result_text = response.content[0].text.strip()
            # Parser la réponse JSON
            try:
                result = json.loads(result_text)
                level = result.get('level', 'GREEN')
                description = result.get('description', 'Analysis completed')
                recommendation = result.get('recommendation', 'SAFE_DESTINATION')
                justification = result.get('justification', '')
                
                # Convertir en format attendu
                if level == 'RED':
                    emoji = "🔴"
                    advice = "🚫 CHANGE DESTINATION - " + justification
                elif level == 'YELLOW':
                    emoji = "🟡"
                    advice = "⚠️ Travel possible with enhanced precautions - " + justification
                else:
                    emoji = "🟢"
                    advice = "✅ Destination considered safe - " + justification
                
                return (emoji, description, advice)
                
            except json.JSONDecodeError:
                return None
                
        except Exception:
            return None



    def _get_current_events_info(self, country: str) -> str:
        """Retrieves current events via web search"""
        try:
            # Search for recent events
            events_keywords = f"{country} current events news today recent"
            events_data = self._search_current_events(events_keywords)
            
            if not events_data:
                return f"📅 **Events**: No major events detected for {country}"
            
            result = f"📅 **Current Events and Context**\n"
            for i, event in enumerate(events_data[:5], 1):
                title = event.get('title', 'Event not specified')
                result += f"• {title}\n"
            
            return result.rstrip()
            
        except Exception:
            return "📅 **Events**: Error during retrieval"

    def _search_current_events(self, keywords: str) -> list:
        """Recherche d'événements actuels"""
        try:
            # Utiliser NewsAPI si disponible
            api_key = os.getenv('NEWSAPI_KEY')
            if api_key:
                url = "https://newsapi.org/v2/everything"
                params = {
                    'q': keywords,
                    'sortBy': 'publishedAt',
                    'pageSize': 5,
                    'from': (datetime.now() - timedelta(days=7)).strftime('%Y-%m-%d'),
                    'language': 'en',
                    'apiKey': api_key
                }
                
                response = requests.get(url, params=params, timeout=10)
                if response.status_code == 200:
                    data = response.json()
                    return data.get('articles', [])
            
            return []
            
        except Exception:
            return []

    def _get_holidays_info(self, country: str) -> str:
        """Retrieves national holidays via API"""
        try:
            country_code = self.country_codes.get(country, '')
            
            # If no code in our mapping, try to get it via API
            if not country_code:
                country_code = self._get_country_code_from_api(country)
            
            if not country_code:
                return f"🎉 **Holidays**: Country code not found for {country}"
            
            # Use Calendarific API or similar
            holidays_data = self._fetch_holidays_api(country_code)
            
            if not holidays_data:
                return f"🎉 **Holidays**: Information not available for {country}"
            
            current_month = datetime.now().month
            current_year = datetime.now().year
            
            result = f"🎉 **Holidays and Seasonal Events**\n"
            
            # Filter holidays from current month and upcoming months
            upcoming_holidays = []
            for holiday in holidays_data:
                try:
                    holiday_date = datetime.strptime(holiday.get('date', ''), '%Y-%m-%d')
                    if holiday_date.month >= current_month and holiday_date.year == current_year:
                        upcoming_holidays.append(holiday)
                except:
                    continue
            
            if upcoming_holidays:
                result += f"**Upcoming holidays:**\n"
                for holiday in upcoming_holidays[:5]:
                    name = holiday.get('name', 'Unknown holiday')
                    date = holiday.get('date', '')
                    result += f"• {name} ({date})\n"
            else:
                result += f"**No major holidays scheduled in the coming months**\n"
            
            return result.rstrip()
            
        except Exception:
            return "🎉 **Holidays**: Error during retrieval"

    def _fetch_holidays_api(self, country_code: str) -> list:
        """Récupère les fêtes via API publique"""
        try:
            # Utiliser une API publique de fêtes (exemple: Calendarific, Nager.Date)
            year = datetime.now().year
            url = f"https://date.nager.at/api/v3/PublicHolidays/{year}/{country_code}"
            
            response = requests.get(url, timeout=10)
            if response.status_code == 200:
                return response.json()
            
            return []
            
        except Exception:
            return []

    def _get_travel_info(self, country: str) -> str:
        """Retrieves travel information via REST Countries API"""
        try:
            # Use REST Countries API
            url = f"https://restcountries.com/v3.1/name/{country}"
            response = requests.get(url, timeout=10)
            
            if response.status_code == 200:
                data = response.json()
                if data:
                    country_data = data[0]
                    
                    # Extract information
                    currencies = country_data.get('currencies', {})
                    languages = country_data.get('languages', {})
                    region = country_data.get('region', 'Unknown')
                    
                    currency_name = list(currencies.keys())[0] if currencies else 'Unknown'
                    language_list = list(languages.values()) if languages else ['Unknown']
                    
                    result = f"✈️ **Practical Travel Information**\n"
                    result += f"💰 Currency: {currency_name}\n"
                    result += f"🗣️ Languages: {', '.join(language_list[:3])}\n"
                    result += f"🌍 Region: {region}\n"
                    result += f"📋 Check visa requirements on the country's official website"
                    
                    return result
            
            return f"✈️ **Travel**: Information not available for {country}"
            
        except Exception:
            return "✈️ **Travel**: Error during retrieval"

    def _get_political_info(self, country: str) -> str:
        """Retrieves political context via news search"""
        try:
            # Search for recent political news
            political_keywords = f"{country} politics government election democracy"
            political_data = self._search_political_news(political_keywords)
            
            if not political_data:
                return f"🏛️ **Politics**: Stable situation for {country}"
            
            result = f"🏛️ **Political Context**\n"
            
            # Analyze political news
            for article in political_data[:3]:
                title = article.get('title', '')
                if title:
                    result += f"• {title}\n"
            
            return result.rstrip()
            
        except Exception:
            return "🏛️ **Politics**: Error during retrieval"

    def _search_political_news(self, keywords: str) -> list:
        """Recherche d'actualités politiques"""
        try:
            api_key = os.getenv('NEWSAPI_KEY')
            if api_key:
                url = "https://newsapi.org/v2/everything"
                params = {
                    'q': keywords,
                    'sortBy': 'publishedAt',
                    'pageSize': 5,
                    'from': (datetime.now() - timedelta(days=30)).strftime('%Y-%m-%d'),
                    'language': 'en',
                    'apiKey': api_key
                }
                
                response = requests.get(url, params=params, timeout=10)
                if response.status_code == 200:
                    data = response.json()
                    return data.get('articles', [])
            
            return []
            
        except Exception:
            return []

    def _get_llm_final_recommendation(self, country: str, full_report: str):
        """Uses Claude to generate an intelligent final recommendation"""
        try:
            if not self.claude_client:
                return None
                
            prompt = f"""Analyze this complete report about {country} and provide a concise final recommendation for a traveler:

COMPLETE REPORT:
{full_report}

Your task:
1. Synthesize the most important information
2. Give a clear and actionable recommendation
3. Respond in English, maximum 200 words
4. Use a professional but accessible tone
5. If risks exist, be explicit about precautions

Desired response format:
🎯 **FINAL RECOMMENDATION**
[Your synthetic analysis and recommendation]

If the destination is dangerous, clearly use "CHANGE DESTINATION" in your response."""

            response = self.claude_client.messages.create(
                model="claude-3-opus-20240229",
                max_tokens=250,
                temperature=0.2,
                system="You are an expert travel advisor. Provide clear and practical recommendations.",
                messages=[
                    {"role": "user", "content": prompt}
                ]
            )
            return response.content[0].text.strip()
            
        except Exception:
            return None