import os
import sys
import asyncio
import subprocess
import httpx

current_dir = os.path.dirname(os.path.abspath(__file__))
backend_dir = os.path.join(current_dir, "backend")

if not os.path.exists(backend_dir):
    print(f"❌ Erreur : Le dossier '{backend_dir}' est introuvable.")
    sys.exit(1)
os.chdir(backend_dir)
sys.path.append(".")
try:
    from app.core.config import settings
except ImportError as e:
    print(f"❌ Erreur d'importation des settings : {e}")
    print(f"Vérifie que ton dossier 'app' est bien dans '{backend_dir}'")
    sys.exit(1)

COMPOSE_DIR = "."
NETWORK_NAME = "arc-network"
TOKEN_FILE = ".gitea_token"
PROJECTS = {
    "infra": "arc-infra",
    "ai": "arc-ai",
    "app": "arc-app",
    "sandbox": "arc-sandbox"
}

def run_command(command, cwd=None):
    """Lance une commande système de manière synchrone."""
    print(f"🚀 Exécution : {' '.join(command) if isinstance(command, list) else command}")
    try:
        subprocess.run(command, cwd=cwd, check=True, capture_output=False)
        return True
    except subprocess.CalledProcessError as e:
        print(f"❌ Erreur : {e}")
        return False

async def wait_for_gitea(local_api_url):
    """Attend que l'API HTTP de Gitea soit pleinement initialisée."""
    public_ping_url = f"{local_api_url}/version"
    max_retries = 20
    print("⏳ Attente du démarrage complet de Gitea et des migrations de la base de données...")
    for i in range(max_retries):
        try:
            async with httpx.AsyncClient(verify=False) as client:
                resp = await client.get(public_ping_url)
                if resp.status_code == 200:
                    print("✅ Gitea est prêt et opérationnel.")
                    return True
        except Exception:
            pass
        if i < max_retries - 1:
            await asyncio.sleep(3)
    raise Exception(f"Gitea n'a pas répondu sur {public_ping_url} après plusieurs tentatives.")

async def bootstrap_gitea_agent(settings_obj, local_api_url):
    """Crée un token d'accès d'application pour l'admin."""
    if os.path.exists(TOKEN_FILE):
        with open(TOKEN_FILE, "r") as f:
            token = f.read().strip()
            if token:
                return token
    
    token_url = f"{local_api_url}/users/{settings_obj.gitea_admin_user}/tokens"

    async with httpx.AsyncClient(verify=False) as client:
        resp = await client.post(
            token_url,
            auth=(settings_obj.gitea_admin_user, settings_obj.gitea_admin_password),
            json={
                "name": "dev-agent-token",
                "scopes": ["all"]
            }
        )
        
        if resp.status_code in [200, 201]:
            token_data = resp.json()
            token = token_data.get('token') or token_data.get('sha1')
            if not token:
                raise Exception(f"Format de réponse inconnu pour le token : {token_data}")
            with open(TOKEN_FILE, "w") as f:
                f.write(token)
            return token
        elif resp.status_code in [400, 409]:
            print("⚠️ Le token existe déjà dans Gitea. Réinitialisation...")
            subprocess.run([
                "docker", "exec", "-u", "git", "git-arc",
                "gitea", "admin", "token", "delete",
                "--username", settings_obj.gitea_admin_user,
                "--name", "dev-agent-token"
            ], capture_output=True)
            return await bootstrap_gitea_agent(settings_obj, local_api_url)
        else:
            raise Exception(f"Échec création token : {resp.status_code} - {resp.text}")
        
async def main():
    # 1. Réseau
    print("--- ÉTAPE 1 : RÉSEAU ---")
    create_net = subprocess.run(
        ["docker", "network", "create", NETWORK_NAME],
        capture_output=True, text=True, shell=(os.name == 'nt')
    )
    if create_net.returncode == 0:
        print(f"✅ Réseau '{NETWORK_NAME}' créé.")
    else:
        print(f"✅ Réseau '{NETWORK_NAME}' déjà présent ou géré.")

    # 2. Infrastructure
    print(f"\n--- ÉTAPE 2 : INFRASTRUCTURE (Projet: {PROJECTS['infra']}) ---")
    infra_cmd = [
        "docker", "compose", 
        "-p", PROJECTS["infra"], 
        "-f", f"{COMPOSE_DIR}/docker-compose-infra.yml", 
        "up", "-d"
    ]
    if not run_command(infra_cmd):
        sys.exit(1)

    # 3. Provisioning Gitea
    print("\n--- ÉTAPE 3 : PROVISIONING GITEA ---")
    
    local_api_url = settings.gitea_api_url.replace("git-arc", "localhost")
    
    # Étape critique : on attend d'abord que le service web et la DB soient OK
    try:
        await wait_for_gitea(local_api_url)
    except Exception as e:
        print(f"❌ Erreur critique de démarrage : {e}")
        sys.exit(1)
    
    print("👤 Création / Vérification du compte administrateur Gitea...")
    result = subprocess.run([
        "docker", "exec", "-u", "git", "git-arc", 
        "gitea", "admin", "user", "create", 
        "--username", settings.gitea_admin_user, 
        "--password", settings.gitea_admin_password, 
        "--email", "admin@arc.local", 
        "--admin"
    ], capture_output=True, text=True)

    if result.returncode == 0:
        print("👤 Compte administrateur créé avec succès.")
    elif "user already exists" in result.stderr:
        print("👤 Compte administrateur existant et valide.")
    else:
        print(f"⚠️ Note Gitea CLI : {result.stderr.strip()}")
    
    try:
        agent_token = await bootstrap_gitea_agent(settings, local_api_url)
        os.environ["GITEA_TOKEN"] = agent_token
        print("✅ Provisioning Gitea réussi, token généré.")
    except Exception as e:
        print(f"❌ Erreur critique de provisioning : {e}")
        sys.exit(1)

    # 4. IA
    print(f"\n--- ÉTAPE 4 : IA (Projet: {PROJECTS['ai']}) ---")
    ai_cmd = [
        "docker", "compose", 
        "-p", PROJECTS["ai"], 
        "-f", f"{COMPOSE_DIR}/docker-compose-ai.yml", 
        "up", "-d"
    ]
    if not run_command(ai_cmd):
        sys.exit(1)

    print(f"\n--- ÉTAPE 5 : Sandbox (Projet: {PROJECTS['sandbox']}) ---")
    sandbox_cmd = [
        "docker", "compose", 
        "-p", PROJECTS["sandbox"], 
        "-f", f"{COMPOSE_DIR}/docker-compose-sandbox.yml", 
        "up", "-d", "--build"
    ]
    if not run_command(sandbox_cmd):
        sys.exit(1)

    # 5. Application
    print(f"\n--- ÉTAPE 6 : APPLICATION (Projet: {PROJECTS['app']}) ---")
    app_cmd = [
        "docker", "compose", 
        "-p", PROJECTS["app"], 
        "-f", f"{COMPOSE_DIR}/docker-compose.yml", 
        "up", "-d", "--build"
    ]
    run_command(app_cmd)

if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        print("\n🛑 Arrêt demandé par l'utilisateur.")