#!/usr/bin/env python3
from __future__ import annotations

import json
import fcntl
import os
import subprocess
import sys
from pathlib import Path

sys.path.insert(0, '/home/agent/projects/CryptoTradingBot/Crypto_Agent')
from src.tools.paper_runtime_supervisor import CANDIDATES, inspect_candidate

REPO = Path('/home/agent/projects/CryptoTradingBot/Crypto_Agent')
PYTHON = REPO / '.venv/bin/python'
RUNTIME_ROOT = REPO / 'runtime/experiments'
LOG_ROOT = Path('/home/agent/.local/state/CryptoTradingBot/v78_logs')
MARKER = Path('/home/agent/.local/state/CryptoTradingBot/v78_supervisor_markers.json')
LOCK = Path('/home/agent/.local/state/CryptoTradingBot/v78_supervisor.lock')
STRATEGIES = (
    'research_v78_2_confirmed_range_reversion',
)


def start(strategy_id: str) -> int:
    LOG_ROOT.mkdir(parents=True, exist_ok=True)
    spec = CANDIDATES[strategy_id]
    env = {**os.environ, 'PYTHONPATH': '.', 'CTB_STRATEGY_ID': strategy_id, 'CTB_PAPER_TRADING': 'true', 'CTB_DRY_RUN': 'false', 'CTB_LIVE_TRADING_ALLOWED': 'false', 'CTB_LIVE_ORDER_ALLOWED': 'false', 'HL_MAINNET_SIGNED_ACTION': 'false'}
    with (LOG_ROOT / f'{strategy_id}.log').open('ab') as log:
        process = subprocess.Popen([str(PYTHON), '-m', spec.module, '--strategy-id', strategy_id, '--coins', ','.join(spec.coins), '--iterations', '720', '--interval-seconds', '60', '--json'], cwd=REPO, env=env, stdout=log, stderr=subprocess.STDOUT, start_new_session=True)
    return process.pid


def promotion(strategy_id: str) -> dict:
    spec = CANDIDATES[strategy_id]
    process = subprocess.run([str(PYTHON), '-m', 'src.tools.v77_promotion_report', '--runtime-dir', str(RUNTIME_ROOT / strategy_id), '--strategy-version', spec.strategy_version, '--json'], cwd=REPO, env={**os.environ, 'PYTHONPATH': '.'}, text=True, capture_output=True, timeout=120)
    if process.returncode != 0:
        raise RuntimeError((process.stderr or process.stdout)[-300:])
    return json.loads(process.stdout)


def refresh_maker_taker_report(strategy_id: str) -> None:
    if strategy_id != 'research_v78_regime_router':
        return
    process = subprocess.run([str(PYTHON), '-m', 'src.tools.maker_taker_shadow_report', '--runtime-dir', str(RUNTIME_ROOT / strategy_id)], cwd=REPO, env={**os.environ, 'PYTHONPATH': '.'}, text=True, capture_output=True, timeout=120)
    if process.returncode != 0:
        raise RuntimeError((process.stderr or process.stdout)[-300:])


def load_markers() -> dict:
    try:
        return json.loads(MARKER.read_text())
    except Exception:
        return {}


def main() -> int:
    LOCK.parent.mkdir(parents=True, exist_ok=True)
    lock = LOCK.open('w')
    try:
        fcntl.flock(lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
    except BlockingIOError:
        return 0
    messages = []
    markers = load_markers()
    for strategy_id in STRATEGIES:
        assessment = inspect_candidate(CANDIDATES[strategy_id], runtime_root=RUNTIME_ROOT)
        if assessment.restart_allowed:
            pid = start(strategy_id)
            messages.append(f'⚙️ v78 Research-Supervisor startete {strategy_id} neu (PID {pid}); paper=true, live=false, signed=false.')
        elif assessment.state != 'healthy':
            messages.append(f'⚠️ v78 Prozesslage {strategy_id}: {assessment.state}; kein blinder Neustart, blocker={",".join(assessment.blockers[:4])}.')
        try:
            report = promotion(strategy_id)
            refresh_maker_taker_report(strategy_id)
        except Exception as exc:
            messages.append(f'⚠️ v78 Promotion-Report fehlgeschlagen: {strategy_id}: {type(exc).__name__}')
            continue
        eligible = report.get('promotion_eligible') is True
        if eligible and not markers.get(strategy_id):
            messages.append(f'🟢 v78 Paper-Gates erstmals erfüllt: {strategy_id}; weiterhin Research-only, manueller Review erforderlich.')
        markers[strategy_id] = eligible
    MARKER.parent.mkdir(parents=True, exist_ok=True)
    MARKER.write_text(json.dumps(markers, indent=2, sort_keys=True))
    if messages:
        print('\n'.join(messages))
    return 0


if __name__ == '__main__':
    raise SystemExit(main())
