#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
🔗 MAPPER - ICHIGRIDEA PIPELINE
═══════════════════════════════════════════════════════════════
Relie le plan (specs) au code (modules).

Usage:
    python mapper.py --map
    python mapper.py --orphans
    python mapper.py --missing
"""

import json
import os
import re
from datetime import datetime
from pathlib import Path


class Mapper:
    def __init__(self, base_dir: str = "."):
        self.base_dir = Path(base_dir)
        self.include_dir = self.base_dir / "Include"
        
        # Charger les registres
        self.modules_registry = self._load_json("MODULES_REGISTRY.json")
        self.dependencies = self._load_json("DEPENDENCIES_GRAPH.json")
        
    def _load_json(self, filename: str) -> dict:
        """Charge un fichier JSON"""
        filepath = self.base_dir / filename
        if filepath.exists():
            with open(filepath, "r", encoding="utf-8") as f:
                return json.load(f)
        return {}
    
    def _extract_section_from_file(self, filepath: Path) -> str:
        """Extrait le @section d'un fichier MQH"""
        try:
            with open(filepath, "r", encoding="utf-8", errors="ignore") as f:
                content = f.read(2000)  # Lire le début seulement
            
            match = re.search(r"@section\s*:\s*(\S+)", content)
            if match:
                return match.group(1)
        except:
            pass
        
        return ""
    
    def map_all(self) -> dict:
        """Crée le mapping complet plan -> code"""
        mapping = {
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "mappings": {},
            "orphan_files": [],
            "missing_implementations": [],
            "statistics": {}
        }
        
        # Scanner les fichiers
        file_sections = {}
        for filepath in self.include_dir.glob("*.mqh"):
            section = self._extract_section_from_file(filepath)
            file_sections[filepath.stem] = {
                "file": str(filepath.relative_to(self.base_dir)),
                "section": section,
                "has_section": bool(section)
            }
        
        # Créer les mappings
        registered_modules = self.modules_registry.get("modules", {})
        
        for module_name, info in file_sections.items():
            if info["section"]:
                mapping["mappings"][info["section"]] = {
                    "module": module_name,
                    "file": info["file"],
                    "source": "tag"
                }
            else:
                # Essayer de trouver dans le registre
                if module_name in registered_modules:
                    section = registered_modules[module_name].get("section", "")
                    if section:
                        mapping["mappings"][section] = {
                            "module": module_name,
                            "file": info["file"],
                            "source": "registry"
                        }
                    else:
                        mapping["orphan_files"].append(module_name)
                else:
                    mapping["orphan_files"].append(module_name)
        
        # Trouver les sections non implémentées
        # (depuis MODULES_REGISTRY ou autre source de specs)
        for module_name, info in registered_modules.items():
            section = info.get("section", "")
            if section and section not in mapping["mappings"]:
                if module_name not in [m["module"] for m in mapping["mappings"].values()]:
                    mapping["missing_implementations"].append({
                        "section": section,
                        "expected_module": module_name
                    })
        
        # Statistiques
        mapping["statistics"] = {
            "total_files": len(file_sections),
            "mapped": len(mapping["mappings"]),
            "orphans": len(mapping["orphan_files"]),
            "missing": len(mapping["missing_implementations"])
        }
        
        return mapping
    
    def find_orphans(self) -> list:
        """Trouve les fichiers sans section associée"""
        mapping = self.map_all()
        return mapping["orphan_files"]
    
    def find_missing(self) -> list:
        """Trouve les sections sans implémentation"""
        mapping = self.map_all()
        return mapping["missing_implementations"]
    
    def generate_report(self) -> str:
        """Génère un rapport markdown"""
        mapping = self.map_all()
        
        report = f"""# 🔗 Rapport de Mapping - IchiGridEA

**Date**: {mapping['timestamp']}

## 📊 Statistiques

| Métrique | Valeur |
|----------|--------|
| Fichiers totaux | {mapping['statistics']['total_files']} |
| Mappés | {mapping['statistics']['mapped']} |
| Orphelins | {mapping['statistics']['orphans']} |
| Non implémentés | {mapping['statistics']['missing']} |

## ✅ Mappings ({len(mapping['mappings'])})

| Section | Module | Source |
|---------|--------|--------|
"""
        for section, info in sorted(mapping['mappings'].items()):
            report += f"| {section} | {info['module']} | {info['source']} |\n"
        
        report += f"""
## 👻 Fichiers orphelins ({len(mapping['orphan_files'])})

"""
        for orphan in mapping['orphan_files']:
            report += f"- {orphan}.mqh\n"
        
        report += f"""
## ❌ Sections non implémentées ({len(mapping['missing_implementations'])})

"""
        for missing in mapping['missing_implementations']:
            report += f"- {missing['section']} → {missing['expected_module']}\n"
        
        return report
    
    def save_mapping(self, output_file: str = "MAPPING.json"):
        """Sauvegarde le mapping en JSON"""
        mapping = self.map_all()
        
        with open(output_file, "w", encoding="utf-8") as f:
            json.dump(mapping, f, indent=2, ensure_ascii=False)
        
        print(f"✅ Mapping sauvegardé: {output_file}")
        return mapping


if __name__ == "__main__":
    import sys
    
    mapper = Mapper()
    
    if "--map" in sys.argv:
        mapper.save_mapping()
        
    elif "--orphans" in sys.argv:
        orphans = mapper.find_orphans()
        print(f"👻 Fichiers orphelins ({len(orphans)}):")
        for o in orphans:
            print(f"   - {o}")
            
    elif "--missing" in sys.argv:
        missing = mapper.find_missing()
        print(f"❌ Sections non implémentées ({len(missing)}):")
        for m in missing:
            print(f"   - {m['section']} → {m['expected_module']}")
            
    elif "--report" in sys.argv:
        report = mapper.generate_report()
        print(report)
        
        # Sauvegarder
        with open("pipeline/reports/mapping_report.md", "w") as f:
            f.write(report)
        print("\n📄 Rapport sauvegardé: pipeline/reports/mapping_report.md")
        
    else:
        print(__doc__)
