#!/usr/bin/env python3
"""
═══════════════════════════════════════════════════════════════
🏗️ SCAFFOLD GENERATOR - ICHIGRIDEA PIPELINE
═══════════════════════════════════════════════════════════════
Génère automatiquement les fichiers MQH à partir des specs.

Usage:
    python scaffold_generator.py --generate S109 --spec "Description"
    python scaffold_generator.py --from-excel EA_Master_UNIFIED.xlsx
    python scaffold_generator.py --dry-run S109
"""

import json
import os
import hashlib
from datetime import datetime
from pathlib import Path
from string import Template


class ScaffoldGenerator:
    def __init__(self, base_dir: str = "."):
        self.base_dir = Path(base_dir)
        self.template_path = self.base_dir / "pipeline/templates/module_template.mqh"
        self.include_dir = self.base_dir / "Include"
        
        # Charger les règles de nommage
        naming_rules_path = self.base_dir / "pipeline/config/naming_rules.json"
        if naming_rules_path.exists():
            with open(naming_rules_path, "r") as f:
                self.naming_rules = json.load(f)
        else:
            self.naming_rules = {}
    
    def generate_session_id(self) -> str:
        """Génère un ID de session unique"""
        import random
        import string
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        suffix = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
        return f"{timestamp}_{suffix}"
    
    def calculate_sha256(self, content: str) -> str:
        """Calcule le SHA-256 d'un contenu"""
        return hashlib.sha256(content.encode("utf-8")).hexdigest()
    
    def load_template(self) -> str:
        """Charge le template de module"""
        if not self.template_path.exists():
            raise FileNotFoundError(f"Template non trouvé: {self.template_path}")
        
        with open(self.template_path, "r", encoding="utf-8") as f:
            return f.read()
    
    def generate_module(
        self,
        section_id: str,
        module_name: str,
        description: str = "",
        version: str = "1.00",
        dependencies: list = None,
        spec_hash: str = "",
        spec_source: str = "",
        dry_run: bool = False
    ) -> dict:
        """Génère un module MQH complet"""
        
        session_id = self.generate_session_id()
        timestamp = datetime.utcnow().isoformat() + "Z"
        dependencies = dependencies or []
        
        # Préparer les substitutions
        module_name_upper = module_name.upper()
        
        # Générer les includes
        includes = "\n".join([
            f'#include "{dep}.mqh"' for dep in dependencies
        ]) if dependencies else "// Pas de dépendances"
        
        # Template simplifié pour le test
        content = f'''//+------------------------------------------------------------------+
//|                                              {module_name}.mqh   |
//|                                    Copyright 2026, SOVRALYS LLC  |
//|                                         https://www.sovralys.com |
//+------------------------------------------------------------------+
// <gen:header>
//| @project     : IchiGridEA
//| @section     : {section_id}
//| @version     : {version}
//| @generated   : {timestamp}
//| @session     : {session_id}
//| @model       : claude-opus-4-5-20250514
//| @spec_hash   : {spec_hash}
//| @code_hash   : PENDING
//| @spec_source : {spec_source}
//| @depends     : {", ".join(dependencies) if dependencies else "none"}
//| @description : {description}
// </gen:header>

#property copyright "Copyright 2026, SOVRALYS LLC"
#property link      "https://www.sovralys.com"
#property version   "{version}"
#property strict

#ifndef __{module_name_upper}_MQH__
#define __{module_name_upper}_MQH__

//+------------------------------------------------------------------+
//| INCLUDES                                                          |
//+------------------------------------------------------------------+
{includes}

//+------------------------------------------------------------------+
//| INPUT PARAMETERS                                                  |
//+------------------------------------------------------------------+
input group "=== {module_name} ==="
input bool InpEnable{module_name} = true;    // Activer {module_name}

//+------------------------------------------------------------------+
//| CLASSE PRINCIPALE                                                 |
//+------------------------------------------------------------------+
class C{module_name}
{{
private:
    bool              m_isInitialized;
    string            m_symbol;
    
public:
    C{module_name}() : m_isInitialized(false), m_symbol("") {{}}
    ~C{module_name}() {{ Deinit(); }}
    
    bool Init(string symbol = "")
    {{
        if(m_isInitialized) return true;
        m_symbol = (symbol == "") ? _Symbol : symbol;
        
        // TODO: Implémenter la logique d'initialisation
        
        m_isInitialized = true;
        Print("[{module_name}] Initialisé sur ", m_symbol);
        return true;
    }}
    
    void Deinit()
    {{
        if(!m_isInitialized) return;
        
        // TODO: Implémenter la logique de désinitialisation
        
        m_isInitialized = false;
        Print("[{module_name}] Désinitialisé");
    }}
    
    void OnTick()
    {{
        if(!m_isInitialized) return;
        
        // TODO: Implémenter la logique OnTick
    }}
    
    bool IsInitialized() const {{ return m_isInitialized; }}
}};

// <dev:begin>
//+------------------------------------------------------------------+
//| BLOC DÉVELOPPEUR - LIBRE                                          |
//+------------------------------------------------------------------+
// Ajoutez votre code personnalisé ici
// Ce bloc ne sera JAMAIS écrasé par le générateur

// </dev:begin>

//+------------------------------------------------------------------+
//| FONCTIONS GLOBALES (WRAPPER)                                      |
//+------------------------------------------------------------------+
C{module_name} *g_p{module_name} = NULL;

bool Init{module_name}(string symbol = "")
{{
    if(g_p{module_name} != NULL) return g_p{module_name}.IsInitialized();
    
    g_p{module_name} = new C{module_name}();
    if(g_p{module_name} == NULL)
    {{
        Print("[{module_name}] Allocation mémoire échouée");
        return false;
    }}
    
    return g_p{module_name}.Init(symbol);
}}

void Deinit{module_name}()
{{
    if(g_p{module_name} != NULL)
    {{
        g_p{module_name}.Deinit();
        delete g_p{module_name};
        g_p{module_name} = NULL;
    }}
}}

void OnTick{module_name}()
{{
    if(g_p{module_name} != NULL)
        g_p{module_name}.OnTick();
}}

#endif // __{module_name_upper}_MQH__
'''
        
        # Calculer le hash du code
        code_hash = self.calculate_sha256(content)
        
        # Remplacer PENDING par le hash réel
        content = content.replace("@code_hash   : PENDING", f"@code_hash   : {code_hash}")
        
        # Chemin de sortie
        output_path = self.include_dir / f"{module_name}.mqh"
        
        result = {
            "session_id": session_id,
            "section_id": section_id,
            "module_name": module_name,
            "output_path": str(output_path),
            "spec_hash": spec_hash,
            "code_hash": code_hash,
            "lines": len(content.split("\n")),
            "timestamp": timestamp,
            "dry_run": dry_run
        }
        
        if dry_run:
            print(f"🔍 DRY-RUN: {output_path}")
            print(f"   Session: {session_id}")
            print(f"   Lines: {result['lines']}")
            print(f"   Code SHA-256: {code_hash[:16]}...")
        else:
            # Créer le fichier
            self.include_dir.mkdir(exist_ok=True)
            with open(output_path, "w", encoding="utf-8") as f:
                f.write(content)
            
            print(f"✅ Généré: {output_path}")
            print(f"   Session: {session_id}")
            print(f"   Lines: {result['lines']}")
        
        return result
    
    def generate_from_spec(self, spec: dict, dry_run: bool = False) -> dict:
        """Génère un module à partir d'une spec"""
        return self.generate_module(
            section_id=spec.get("section_id", "S000"),
            module_name=spec.get("module_name", "NewModule"),
            description=spec.get("description", ""),
            version=spec.get("version", "1.00"),
            dependencies=spec.get("dependencies", []),
            spec_hash=spec.get("spec_hash", ""),
            spec_source=spec.get("spec_source", ""),
            dry_run=dry_run
        )


if __name__ == "__main__":
    import sys
    
    generator = ScaffoldGenerator()
    
    if "--generate" in sys.argv:
        try:
            idx = sys.argv.index("--generate")
            section_id = sys.argv[idx + 1]
            
            # Extraire le nom du module (S109 -> ModuleS109)
            module_name = f"Module{section_id}"
            
            # Description optionnelle
            description = ""
            if "--spec" in sys.argv:
                spec_idx = sys.argv.index("--spec")
                description = sys.argv[spec_idx + 1]
            
            generator.generate_module(
                section_id=section_id,
                module_name=module_name,
                description=description
            )
            
        except IndexError:
            print("Usage: python scaffold_generator.py --generate S109 --spec 'Description'")
            sys.exit(1)
            
    elif "--dry-run" in sys.argv:
        try:
            idx = sys.argv.index("--dry-run")
            section_id = sys.argv[idx + 1]
            module_name = f"Module{section_id}"
            
            generator.generate_module(
                section_id=section_id,
                module_name=module_name,
                dry_run=True
            )
        except IndexError:
            print("Usage: python scaffold_generator.py --dry-run S109")
            sys.exit(1)
            
    else:
        print(__doc__)
