#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
📸 SNAPSHOT MANAGER - ICHIGRIDEA PIPELINE
═══════════════════════════════════════════════════════════════
Capture et compare les états du projet

Usage:
    python snapshot_manager.py --capture
    python snapshot_manager.py --diff <date1> <date2>
    python snapshot_manager.py --list
"""

import json
import os
import shutil
from datetime import datetime
from pathlib import Path
import hashlib


class SnapshotManager:
    def __init__(self, base_dir: str = ".", snapshots_dir: str = "pipeline/snapshots"):
        self.base_dir = Path(base_dir)
        self.snapshots_dir = self.base_dir / snapshots_dir
        self.snapshots_dir.mkdir(parents=True, exist_ok=True)
    
    def get_snapshot_name(self) -> str:
        """Génère un nom de snapshot basé sur la date"""
        return datetime.now().strftime("%Y-%m-%d_%H%M%S")
    
    def calculate_file_hash(self, filepath: Path) -> str:
        """Calcule le SHA-256 d'un fichier"""
        sha256 = hashlib.sha256()
        with open(filepath, "rb") as f:
            for chunk in iter(lambda: f.read(4096), b""):
                sha256.update(chunk)
        return sha256.hexdigest()
    
    def capture(self, name: str = None) -> str:
        """Capture un snapshot de l'état actuel"""
        if name is None:
            name = self.get_snapshot_name()
        
        snapshot_path = self.snapshots_dir / name
        snapshot_path.mkdir(exist_ok=True)
        
        print(f"📸 Capture du snapshot: {name}")
        
        # Fichiers à capturer
        files_to_capture = [
            "STATE.json",
            "MODULES_REGISTRY.json",
            "DEPENDENCIES_GRAPH.json",
            "INPUTS_REGISTRY.json",
            "STRUCTURES_SCHEMA.json",
            "HASHMAP.json"
        ]
        
        captured = []
        hashes = {}
        
        for filename in files_to_capture:
            src = self.base_dir / filename
            if src.exists():
                dst = snapshot_path / filename
                shutil.copy2(src, dst)
                hashes[filename] = self.calculate_file_hash(src)
                captured.append(filename)
                print(f"   ✅ {filename}")
        
        # Calculer les hashes de tous les modules
        include_dir = self.base_dir / "Include"
        modules_hashes = {}
        if include_dir.exists():
            for mqh in include_dir.glob("*.mqh"):
                modules_hashes[mqh.name] = self.calculate_file_hash(mqh)
        
        # Créer le manifest du snapshot
        manifest = {
            "name": name,
            "timestamp": datetime.utcnow().isoformat() + "Z",
            "files": captured,
            "file_hashes": hashes,
            "modules_count": len(modules_hashes),
            "modules_hashes": modules_hashes
        }
        
        manifest_path = snapshot_path / "MANIFEST.json"
        with open(manifest_path, "w", encoding="utf-8") as f:
            json.dump(manifest, f, indent=2)
        
        print(f"\n✅ Snapshot capturé: {snapshot_path}")
        print(f"   Fichiers: {len(captured)}")
        print(f"   Modules: {len(modules_hashes)}")
        
        return name
    
    def list_snapshots(self) -> list:
        """Liste tous les snapshots disponibles"""
        snapshots = []
        
        for item in sorted(self.snapshots_dir.iterdir()):
            if item.is_dir():
                manifest_path = item / "MANIFEST.json"
                if manifest_path.exists():
                    with open(manifest_path, "r") as f:
                        manifest = json.load(f)
                    snapshots.append({
                        "name": item.name,
                        "timestamp": manifest.get("timestamp"),
                        "modules_count": manifest.get("modules_count", 0)
                    })
        
        return snapshots
    
    def diff(self, snapshot1: str, snapshot2: str) -> dict:
        """Compare deux snapshots"""
        path1 = self.snapshots_dir / snapshot1 / "MANIFEST.json"
        path2 = self.snapshots_dir / snapshot2 / "MANIFEST.json"
        
        if not path1.exists():
            raise FileNotFoundError(f"Snapshot non trouvé: {snapshot1}")
        if not path2.exists():
            raise FileNotFoundError(f"Snapshot non trouvé: {snapshot2}")
        
        with open(path1, "r") as f:
            manifest1 = json.load(f)
        with open(path2, "r") as f:
            manifest2 = json.load(f)
        
        hashes1 = manifest1.get("modules_hashes", {})
        hashes2 = manifest2.get("modules_hashes", {})
        
        modules1 = set(hashes1.keys())
        modules2 = set(hashes2.keys())
        
        added = modules2 - modules1
        removed = modules1 - modules2
        common = modules1 & modules2
        
        modified = {m for m in common if hashes1[m] != hashes2[m]}
        unchanged = common - modified
        
        result = {
            "snapshot1": snapshot1,
            "snapshot2": snapshot2,
            "timestamp1": manifest1.get("timestamp"),
            "timestamp2": manifest2.get("timestamp"),
            "added": sorted(added),
            "removed": sorted(removed),
            "modified": sorted(modified),
            "unchanged_count": len(unchanged)
        }
        
        return result
    
    def generate_diff_report(self, snapshot1: str, snapshot2: str) -> str:
        """Génère un rapport de diff en markdown"""
        diff = self.diff(snapshot1, snapshot2)
        
        report = f"""# 📊 Diff Report: {snapshot1} → {snapshot2}

**Snapshot 1**: {diff['timestamp1']}
**Snapshot 2**: {diff['timestamp2']}

## Résumé

| Changement | Nombre |
|------------|--------|
| ➕ Ajoutés | {len(diff['added'])} |
| ➖ Supprimés | {len(diff['removed'])} |
| ✏️ Modifiés | {len(diff['modified'])} |
| ✅ Inchangés | {diff['unchanged_count']} |

## ➕ Modules ajoutés
"""
        for m in diff['added']:
            report += f"- {m}\n"
        
        report += "\n## ➖ Modules supprimés\n"
        for m in diff['removed']:
            report += f"- {m}\n"
        
        report += "\n## ✏️ Modules modifiés\n"
        for m in diff['modified']:
            report += f"- {m}\n"
        
        return report


if __name__ == "__main__":
    import sys
    
    manager = SnapshotManager()
    
    if "--capture" in sys.argv:
        name = None
        try:
            idx = sys.argv.index("--capture")
            if idx + 1 < len(sys.argv) and not sys.argv[idx + 1].startswith("--"):
                name = sys.argv[idx + 1]
        except:
            pass
        manager.capture(name)
        
    elif "--list" in sys.argv:
        snapshots = manager.list_snapshots()
        print("📸 Snapshots disponibles:")
        print("-" * 50)
        for s in snapshots:
            print(f"  {s['name']} ({s['modules_count']} modules) - {s['timestamp']}")
        
    elif "--diff" in sys.argv:
        try:
            idx = sys.argv.index("--diff")
            snapshot1 = sys.argv[idx + 1]
            snapshot2 = sys.argv[idx + 2]
            
            report = manager.generate_diff_report(snapshot1, snapshot2)
            print(report)
            
            # Sauvegarder le rapport
            report_path = f"pipeline/reports/diff_{snapshot1}_vs_{snapshot2}.md"
            with open(report_path, "w") as f:
                f.write(report)
            print(f"\n📄 Rapport sauvegardé: {report_path}")
            
        except IndexError:
            print("Usage: python snapshot_manager.py --diff <snapshot1> <snapshot2>")
            sys.exit(1)
    else:
        print(__doc__)
