"""
candy.vps — Module VPS v17
===========================
Gère la connexion WebSocket interactive au VPS Cédric7-Thinking
et l'exécution de fichiers distants.

Commandes CLI :
  candy vps --token XXXXX           → Session interactive (type SSH)
  candy --efile "script.py" --token XXXXX → Exécute un fichier sur le VPS

API Python :
  from candy.vps import VPS
  VPS.exec("mon_script.py", token="XXXXX")    # exécute + affiche output
  VPS.session(token="XXXXX")                  # session interactive
"""

import json
import os
import sys
import threading
import time
from pathlib import Path
from typing import Optional

CANDY_JSON_URL = "https://candy-gate.hubworld.net/candy.json"
_TOKEN_FILE    = Path.home() / ".candy" / "vps_token.txt"


# ══════════════════════════════════════════════════════════════════════════════
# Résolution de l'URL du serveur VPS (via candy.json)
# ══════════════════════════════════════════════════════════════════════════════

def _get_vps_base() -> str:
    """Récupère l'URL de base du serveur VPS depuis candy.json."""
    import httpx
    try:
        r = httpx.get(CANDY_JSON_URL, timeout=8)
        r.raise_for_status()
        data = r.json()
        if data.get("is_closed", True):
            raise ConnectionError("Serveur VPS hors ligne.")
        link = data.get("link", "").strip().rstrip("/")
        if not link:
            raise ConnectionError("Aucune URL dans candy.json")
        return link
    except ConnectionError:
        raise
    except Exception as e:
        raise ConnectionError(f"Impossible de joindre candy.json : {e}")


# ══════════════════════════════════════════════════════════════════════════════
# Session interactive (WebSocket)
# ══════════════════════════════════════════════════════════════════════════════

def _run_session(token: str):
    """
    Lance une session VPS interactive dans le terminal.
    Bloque jusqu'à ce que l'utilisateur tape 'exit'.
    """
    try:
        import websocket  # websocket-client
    except ImportError:
        print("\033[91mInstalle websocket-client : pip install websocket-client\033[0m")
        sys.exit(1)

    base = _get_vps_base()
    ws_url = base.replace("https://", "wss://").replace("http://", "ws://")
    ws_url += f"/vps/session/{token}"

    gray   = "\033[90m"
    cyan   = "\033[96m"
    green  = "\033[92m"
    red    = "\033[91m"
    reset  = "\033[0m"

    connected = threading.Event()
    done      = threading.Event()

    def on_message(ws, message):
        try:
            data = json.loads(message)
            kind = data.get("kind", "output")
            text = data.get("data", "")
        except Exception:
            print(message, end="")
            return

        if kind == "welcome":
            print(f"\n{cyan}{text}{reset}", end="")
            connected.set()
        elif kind == "error":
            print(f"{red}{text}{reset}", end="")
        elif kind == "info":
            print(f"{gray}{text}{reset}", end="")
        elif kind == "output":
            print(text, end="", flush=True)

    def on_error(ws, error):
        print(f"\n{red}Erreur WebSocket : {error}{reset}")
        done.set()

    def on_close(ws, code, msg):
        print(f"\n{gray}[candy vps] Session fermée.{reset}\n")
        done.set()

    def on_open(ws):
        pass

    ws = websocket.WebSocketApp(
        ws_url,
        on_open=on_open,
        on_message=on_message,
        on_error=on_error,
        on_close=on_close,
    )

    # Thread pour recevoir les messages
    t = threading.Thread(target=ws.run_forever, daemon=True)
    t.start()

    # Attendre la connexion
    if not connected.wait(timeout=10):
        print(f"{red}Timeout : impossible de se connecter au VPS.{reset}")
        ws.close()
        return

    # Boucle de saisie
    prompt = f"{green}candy@vps{reset}{gray}:~${reset} "
    try:
        while not done.is_set():
            try:
                cmd = input(prompt)
            except EOFError:
                break
            except KeyboardInterrupt:
                print()
                cmd = "exit"

            ws.send(json.dumps({"cmd": cmd}))

            if cmd.strip().lower() in ("exit", "quit"):
                time.sleep(0.3)
                break

            # Petit délai pour laisser la réponse arriver
            time.sleep(0.1)
    finally:
        ws.close()


# ══════════════════════════════════════════════════════════════════════════════
# Exécution d'un fichier distant (SSE)
# ══════════════════════════════════════════════════════════════════════════════

def _run_efile(filepath: str, token: str):
    """
    Exécute un fichier stocké sur le VPS et affiche l'output en temps réel.
    Utilise SSE (Server-Sent Events) pour le streaming.
    """
    try:
        import httpx
    except ImportError:
        print("\033[91mInstalle httpx : pip install httpx\033[0m")
        sys.exit(1)

    base = _get_vps_base()
    url  = f"{base}/vps/exec"

    gray  = "\033[90m"
    cyan  = "\033[96m"
    green = "\033[92m"
    red   = "\033[91m"
    reset = "\033[0m"

    print(f"\n{gray}[candy vps] Exécution : {filepath}{reset}\n")

    with httpx.Client(timeout=None) as client:
        with client.stream("POST", url, data={"token": token, "filepath": filepath}) as r:
            if r.status_code == 403:
                print(f"{red}⛔ Token invalide ou accès refusé.{reset}")
                return
            if r.status_code == 404:
                print(f"{red}⛔ Fichier introuvable sur le VPS : {filepath}{reset}")
                return
            if r.status_code == 429:
                print(f"{red}⛔ Trop de processus actifs (max 5). Utilisez 'candy vps --token ... kill' pour les arrêter.{reset}")
                return
            if r.status_code == 400:
                detail = r.read().decode()
                print(f"{red}⛔ Script bloqué par sécurité : {detail}{reset}")
                return
            if not r.is_success:
                print(f"{red}Erreur {r.status_code}{reset}")
                return

            for line in r.iter_lines():
                if not line.startswith("data:"):
                    continue
                raw = line[5:].strip()
                if not raw:
                    continue
                try:
                    event = json.loads(raw)
                except Exception:
                    continue

                kind = event.get("kind", "")
                if kind == "start":
                    fname = event.get("file", filepath)
                    print(f"{cyan}▶ {fname}{reset}")
                elif kind == "output":
                    print(event.get("data", ""), end="", flush=True)
                elif kind == "done":
                    code = event.get("code", 0)
                    col  = green if code == 0 else red
                    sym  = "✅" if code == 0 else "❌"
                    print(f"\n{col}{sym} Terminé (code {code}){reset}")
                elif kind == "timeout":
                    print(f"\n{red}⏱️  Timeout — processus arrêté.{reset}")
                elif kind == "error":
                    print(f"\n{red}Erreur : {event.get('data','')}{reset}")


# ══════════════════════════════════════════════════════════════════════════════
# Classe publique (API Python)
# ══════════════════════════════════════════════════════════════════════════════

class VPS:
    """
    Interface Python pour le VPS Cédric7-Thinking.

    Exemples :
        from candy.vps import VPS
        VPS.exec("mon_script.py", token="XXXXX")
        VPS.session(token="XXXXX")
    """

    @staticmethod
    def exec(filepath: str, token: str):
        """Exécute un fichier sur le VPS et affiche l'output."""
        _run_efile(filepath, token)

    @staticmethod
    def session(token: str):
        """Lance une session interactive."""
        _run_session(token)

    @staticmethod
    def status(token: str) -> dict:
        """Retourne le statut des processus actifs."""
        import httpx
        base = _get_vps_base()
        r = httpx.get(f"{base}/vps/processes", params={"token": token}, timeout=8)
        r.raise_for_status()
        return r.json()

    @staticmethod
    def files(token: str, path: str = "") -> dict:
        """Liste les fichiers du sandbox."""
        import httpx
        base = _get_vps_base()
        r = httpx.get(
            f"{base}/vps/files",
            params={"token": token, "path": path},
            timeout=8,
        )
        r.raise_for_status()
        return r.json()
