#!/usr/bin/env python3
"""
Mavis Supervisor Watchdog — controlla ogni 60s se mavis_supervisor_3.py e' vivo.
Se muore, lo rilancia in background con env Bybit + WEBHOOK_SECRET.
FIX 2026-07-16: serve a non lasciare Mattia scoperto di notte.
- Gira in loop infinito (lo lancia boot_recovery.ps1 al logon + supervisore lo monitora)
- Se supervisore muore, watchdog lo rilancia in 60s
- Usa psutil (no PowerShell popup)
- Usa pythonw.exe (no console) per i processi lanciati
"""
import os
import sys
import time
import subprocess
import psutil
from pathlib import Path

ROOT = Path(r"G:\AI TRADING ENGINE\live_deploy")
LOG_FILE = ROOT / "webhook_listener" / "logs" / "supervisor_watchdog.log"
ENV_FILE = Path(r"G:\AI TRADING ENGINE\API_KEY_BYBIT.env")
PYW = r"C:\Users\Mattia\AppData\Local\Programs\Python\Python314\pythonw.exe"
PYW_FALLBACK = sys.executable  # se pythonw non c'e'
CHECK_INTERVAL = 60
DETACHED_PROCESS = 0x00000008
CREATE_NO_WINDOW = 0x08000000
SUBPROC_FLAGS = DETACHED_PROCESS | CREATE_NO_WINDOW
WEBHOOK_SECRET_DEFAULT = "TV_2026_MATTIA_DEMO"


def log(msg: str) -> None:
    ts = time.strftime("%Y-%m-%d %H:%M:%S")
    line = f"[{ts}] {msg}"
    print(line, flush=True)
    try:
        LOG_FILE.parent.mkdir(parents=True, exist_ok=True)
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(line + "\n")
    except Exception:
        pass


def setup_env() -> None:
    """Legge API_KEY_BYBIT.env e mappa a BYBIT_API_KEY/SECRET + WEBHOOK_SECRET."""
    try:
        for line in ENV_FILE.read_text(encoding="utf-8").splitlines():
            if "=" not in line:
                continue
            k, _, v = line.partition("=")
            k = k.strip()
            v = v.strip()
            if k == "BYBIT_DEMO_API_KEY":
                os.environ["BYBIT_API_KEY"] = v
            elif k == "BYBIT_DEMO_SECRET_KEY":
                os.environ["BYBIT_API_SECRET"] = v
    except Exception as e:
        log(f"[warn] setup_env: {e}")
    os.environ["WEBHOOK_SECRET"] = WEBHOOK_SECRET_DEFAULT


def is_supervisor_alive() -> bool:
    """True se almeno un processo python/pythonw ha 'mavis_supervisor_3.py' nella commandline."""
    try:
        for p in psutil.process_iter(['pid', 'name', 'cmdline']):
            name = (p.info.get('name') or '').lower()
            if 'python' not in name:
                continue
            cmd = ' '.join(p.info.get('cmdline') or [])
            if 'mavis_supervisor_3.py' in cmd:
                return True
    except Exception as e:
        log(f"[warn] is_supervisor_alive fallita: {e}")
    return False


def kill_orphan_supervisors() -> int:
    """Killa TUTTI i processi supervisore (utile prima di rilanciare, evita proliferazione)."""
    killed = 0
    try:
        for p in psutil.process_iter(['pid', 'name', 'cmdline']):
            name = (p.info.get('name') or '').lower()
            if 'python' not in name:
                continue
            cmd = ' '.join(p.info.get('cmdline') or [])
            if 'mavis_supervisor_3.py' in cmd:
                try:
                    p.terminate()
                    try:
                        p.wait(timeout=3)
                    except psutil.TimeoutExpired:
                        p.kill()
                        p.wait(timeout=2)
                    killed += 1
                except Exception:
                    pass
    except Exception as e:
        log(f"[warn] kill_orphan_supervisors fallita: {e}")
    return killed


def launch_supervisor() -> None:
    """Lancia mavis_supervisor_3.py in background con env gia' settate."""
    # Scegli pythonw.exe
    pyw = PYW if Path(PYW).exists() else PYW_FALLBACK
    if pyw == PYW_FALLBACK:
        log(f"[warn] pythonw.exe non trovato in {PYW}, fallback su {pyw}")
    # Log redir
    log_dir = ROOT / "webhook_listener" / "logs"
    log_dir.mkdir(parents=True, exist_ok=True)
    stdout_log = open(log_dir / "mavis_supervisor_3.out.log", "a", encoding="utf-8")
    stderr_log = open(log_dir / "mavis_supervisor_3.err.log", "a", encoding="utf-8")
    subprocess.Popen(
        [pyw, "-u", "mavis_supervisor_3.py"],
        cwd=str(ROOT),
        env=os.environ.copy(),
        stdout=stdout_log,
        stderr=stderr_log,
        creationflags=SUBPROC_FLAGS,
        close_fds=False,
    )
    log(f"[ok] supervisore rilanciato con {os.path.basename(pyw)}")


def main() -> int:
    setup_env()
    log("=" * 60)
    log(f"SUPERVISOR WATCHDOG avviato (check ogni {CHECK_INTERVAL}s)")
    log(f"  psutil version: {psutil.__version__}")
    log(f"  python: {sys.executable}")
    log(f"  env BYBIT_API_KEY (len={len(os.environ.get('BYBIT_API_KEY',''))})")
    log("=" * 60)

    while True:
        try:
            if not is_supervisor_alive():
                log("[ALERT] supervisore NON attivo, rilancio in corso...")
                killed = kill_orphan_supervisors()
                if killed:
                    log(f"  [cleanup] killati {killed} supervisore orfani")
                time.sleep(2)
                launch_supervisor()
                time.sleep(5)  # dai tempo al supervisore di partire
            # else: silenzio (tutto ok)
        except KeyboardInterrupt:
            log("[STOP] KeyboardInterrupt, esco")
            return 0
        except Exception as e:
            log(f"[err] main loop: {e}")
        time.sleep(CHECK_INTERVAL)


if __name__ == "__main__":
    sys.exit(main())
