#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
✅ INTEGRATION VALIDATOR - ICHIGRIDEA PIPELINE
═══════════════════════════════════════════════════════════════
Valide l'intégration des modules dans IchiGridEA.mq5.

Usage:
    python integration_validator.py --validate
    python integration_validator.py --check-includes
    python integration_validator.py --check-calls
    python integration_validator.py --report
"""

import re
import json
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Set, Tuple


class IntegrationValidator:
    """Valide l'intégration des modules dans l'EA principal"""
    
    def __init__(self, base_dir: str = "."):
        self.base_dir = Path(base_dir)
        self.mq5_path = self.base_dir / "IchiGridEA.mq5"
        self.include_dir = self.base_dir / "Include"
        
        self.mq5_content = ""
        self.modules = []
        self.issues = []
        self.warnings = []
        self.info = []
        
    def load(self) -> bool:
        """Charge le fichier EA et liste les modules"""
        if not self.mq5_path.exists():
            self.issues.append("IchiGridEA.mq5 non trouvé")
            return False
        
        with open(self.mq5_path, "r", encoding="utf-8", errors="ignore") as f:
            self.mq5_content = f.read()
        
        # Lister les modules
        if self.include_dir.exists():
            self.modules = [f.stem for f in self.include_dir.glob("*.mqh")]
        
        return True
    
    def get_included_modules(self) -> Set[str]:
        """Retourne les modules inclus dans l'EA"""
        pattern = r'#include\s+"Include/([^"]+)\.mqh"'
        matches = re.findall(pattern, self.mq5_content)
        return set(matches)
    
    def get_init_calls(self) -> Set[str]:
        """Retourne les appels Init dans OnInit()"""
        # Trouver la fonction OnInit
        init_match = re.search(r'int\s+OnInit\s*\(\s*\)[^{]*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}', 
                                self.mq5_content, re.DOTALL)
        if not init_match:
            return set()
        
        init_body = init_match.group(1)
        
        # Trouver les appels Init*()
        pattern = r'Init(\w+)\s*\('
        matches = re.findall(pattern, init_body)
        return set(matches)
    
    def get_deinit_calls(self) -> Set[str]:
        """Retourne les appels Deinit dans OnDeinit()"""
        deinit_match = re.search(r'void\s+OnDeinit\s*\([^)]*\)[^{]*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}',
                                  self.mq5_content, re.DOTALL)
        if not deinit_match:
            return set()
        
        deinit_body = deinit_match.group(1)
        
        pattern = r'Deinit(\w+)\s*\('
        matches = re.findall(pattern, deinit_body)
        return set(matches)
    
    def check_includes(self) -> Dict:
        """Vérifie que tous les modules ont leur #include"""
        included = self.get_included_modules()
        
        missing_includes = []
        for module in self.modules:
            if module not in included:
                missing_includes.append(module)
        
        # Modules inclus mais n'existant pas
        phantom_includes = []
        for inc in included:
            if inc not in self.modules:
                phantom_includes.append(inc)
        
        return {
            "total_modules": len(self.modules),
            "included": len(included),
            "missing_includes": missing_includes,
            "phantom_includes": phantom_includes
        }
    
    def check_init_deinit(self) -> Dict:
        """Vérifie les appels Init/Deinit"""
        init_calls = self.get_init_calls()
        deinit_calls = self.get_deinit_calls()
        
        # Modules avec Init mais sans Deinit
        init_without_deinit = init_calls - deinit_calls
        
        # Modules avec Deinit mais sans Init
        deinit_without_init = deinit_calls - init_calls
        
        return {
            "init_calls": len(init_calls),
            "deinit_calls": len(deinit_calls),
            "init_without_deinit": list(init_without_deinit),
            "deinit_without_init": list(deinit_without_init)
        }
    
    def check_oninit_return(self) -> Dict:
        """Vérifie la structure de OnInit"""
        result = {
            "has_oninit": False,
            "returns_init_succeeded": False,
            "returns_init_failed": False
        }
        
        if "int OnInit()" in self.mq5_content:
            result["has_oninit"] = True
        
        if "INIT_SUCCEEDED" in self.mq5_content:
            result["returns_init_succeeded"] = True
        
        if "INIT_FAILED" in self.mq5_content:
            result["returns_init_failed"] = True
        
        return result
    
    def check_ontick_calls(self) -> Dict:
        """Vérifie les appels dans OnTick"""
        ontick_match = re.search(r'void\s+OnTick\s*\(\s*\)[^{]*\{([^}]+(?:\{[^}]*\}[^}]*)*)\}',
                                  self.mq5_content, re.DOTALL)
        if not ontick_match:
            return {"has_ontick": False, "calls": []}
        
        ontick_body = ontick_match.group(1)
        
        # Trouver les appels de fonction
        pattern = r'(\w+)\s*\('
        calls = re.findall(pattern, ontick_body)
        
        # Filtrer les mots-clés
        keywords = {"if", "while", "for", "switch", "return"}
        calls = [c for c in calls if c not in keywords]
        
        return {
            "has_ontick": True,
            "calls_count": len(calls),
            "calls": calls[:20]  # Limiter à 20
        }
    
    def validate(self) -> Dict:
        """Exécute toutes les validations"""
        if not self.load():
            return {"status": "ERROR", "issues": self.issues}
        
        includes = self.check_includes()
        init_deinit = self.check_init_deinit()
        oninit = self.check_oninit_return()
        ontick = self.check_ontick_calls()
        
        # Collecter les issues
        if includes["missing_includes"]:
            self.warnings.append(f"{len(includes['missing_includes'])} modules non inclus")
        
        if includes["phantom_includes"]:
            self.issues.append(f"{len(includes['phantom_includes'])} includes fantômes")
        
        if init_deinit["init_without_deinit"]:
            self.warnings.append(f"Init sans Deinit: {init_deinit['init_without_deinit']}")
        
        if not oninit["has_oninit"]:
            self.issues.append("OnInit() non trouvé")
        
        if not oninit["returns_init_succeeded"]:
            self.warnings.append("INIT_SUCCEEDED non trouvé")
        
        # Calculer le score
        score = 100
        score -= len(self.issues) * 20
        score -= len(self.warnings) * 5
        score = max(0, score)
        
        return {
            "status": "PASS" if not self.issues else "FAIL",
            "score": score,
            "includes": includes,
            "init_deinit": init_deinit,
            "oninit": oninit,
            "ontick": ontick,
            "issues": self.issues,
            "warnings": self.warnings,
            "timestamp": datetime.utcnow().isoformat() + "Z"
        }
    
    def generate_report(self) -> str:
        """Génère un rapport markdown"""
        result = self.validate()
        
        report = f"""# ✅ Rapport d'Intégration - IchiGridEA

**Date**: {result['timestamp']}
**Statut**: {result['status']}
**Score**: {result['score']}/100

## 📊 Résumé

| Métrique | Valeur |
|----------|--------|
| Modules totaux | {result['includes']['total_modules']} |
| Modules inclus | {result['includes']['included']} |
| Appels Init | {result['init_deinit']['init_calls']} |
| Appels Deinit | {result['init_deinit']['deinit_calls']} |

## ❌ Issues ({len(result['issues'])})

"""
        for issue in result['issues']:
            report += f"- {issue}\n"
        
        report += f"""
## ⚠️ Warnings ({len(result['warnings'])})

"""
        for warning in result['warnings']:
            report += f"- {warning}\n"
        
        if result['includes']['missing_includes']:
            report += f"""
## 📋 Modules non inclus ({len(result['includes']['missing_includes'])})

"""
            for module in result['includes']['missing_includes'][:20]:
                report += f"- {module}\n"
        
        if result['init_deinit']['init_without_deinit']:
            report += f"""
## ⚠️ Init sans Deinit correspondant

"""
            for module in result['init_deinit']['init_without_deinit']:
                report += f"- {module}\n"
        
        return report
    
    def suggest_fixes(self) -> List[str]:
        """Suggère des corrections"""
        suggestions = []
        
        result = self.validate()
        
        for module in result['includes']['missing_includes'][:10]:
            suggestions.append(f'#include "Include/{module}.mqh"')
        
        for module in result['init_deinit']['init_without_deinit']:
            suggestions.append(f"Ajouter Deinit{module}() dans OnDeinit()")
        
        return suggestions


def main():
    import sys
    
    validator = IntegrationValidator()
    
    if "--validate" in sys.argv:
        result = validator.validate()
        
        print(f"📊 Statut: {result['status']}")
        print(f"📊 Score: {result['score']}/100")
        
        if result['issues']:
            print(f"\n❌ Issues ({len(result['issues'])}):")
            for issue in result['issues']:
                print(f"   - {issue}")
        
        if result['warnings']:
            print(f"\n⚠️ Warnings ({len(result['warnings'])}):")
            for warning in result['warnings']:
                print(f"   - {warning}")
                
    elif "--check-includes" in sys.argv:
        if validator.load():
            includes = validator.check_includes()
            print(f"📊 Modules: {includes['total_modules']}")
            print(f"✅ Inclus: {includes['included']}")
            print(f"❌ Manquants: {len(includes['missing_includes'])}")
            
            if includes['missing_includes']:
                print("\nModules manquants:")
                for m in includes['missing_includes'][:10]:
                    print(f"   - {m}")
                    
    elif "--check-calls" in sys.argv:
        if validator.load():
            init_deinit = validator.check_init_deinit()
            print(f"Init(): {init_deinit['init_calls']} appels")
            print(f"Deinit(): {init_deinit['deinit_calls']} appels")
            
    elif "--report" in sys.argv:
        report = validator.generate_report()
        print(report)
        
        # Sauvegarder
        with open("pipeline/reports/integration_report.md", "w") as f:
            f.write(report)
        print("\n📄 Rapport sauvegardé: pipeline/reports/integration_report.md")
        
    elif "--suggest" in sys.argv:
        suggestions = validator.suggest_fixes()
        print("💡 Suggestions de corrections:")
        for s in suggestions:
            print(f"   {s}")
            
    else:
        print(__doc__)


if __name__ == "__main__":
    main()
