"""
regime_detector.py — V2 (Mattia 04/08/2026)
=============================================
Modulo regime detector per bloccare nuove entries quando il mercato e' in panic mode.

Regole:
- Legge candele 1H di BTCUSDT e ETHUSDT
- Calcola % change su finestra 4h e 24h
- Se BTC o ETH crolla > 2.5% in 4h -> STOP nuove entries per 12h
- Se BTC o ETH crolla > 5% in 24h -> STOP nuove entries per 24h
- Stato persistito in regime_state.json (atomic write)

Usage:
    from regime_detector import is_panic, get_state
    if is_panic():
        log("REGIME PANIC: skip entry")
        return
"""
import json
import os
import time
from datetime import datetime, timezone
from pathlib import Path

import requests

STATE_FILE = Path("/opt/charter-live/live_deploy_v2/logs/regime_state.json")
LOG_FILE = Path("/opt/charter-live/live_deploy_v2/logs/regime_detector.log")

PANIC_4H_THRESHOLD = -0.025  # -2.5% in 4h
PANIC_24H_THRESHOLD = -0.05  # -5% in 24h
PANIC_4H_DURATION = 12 * 3600  # 12h in sec
PANIC_24H_DURATION = 24 * 3600  # 24h in sec

BYBIT_BASE = "https://api-demo.bybit.com"
SYMBOLS = ["BTCUSDT", "ETHUSDT"]


def _log(msg):
    ts = datetime.now(timezone.utc).isoformat()
    line = f"[{ts}] {msg}"
    print(line, flush=True)
    try:
        os.makedirs(LOG_FILE.parent, exist_ok=True)
        with open(LOG_FILE, "a", encoding="utf-8") as f:
            f.write(line + "\n")
    except Exception:
        pass


def _load_state():
    try:
        if STATE_FILE.exists():
            with open(STATE_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
    except Exception as e:
        _log(f"load_state err: {e}")
    return {"panic_until": 0, "last_check": 0, "last_4h_chg": {}, "last_24h_chg": {}}


def _save_state(state):
    try:
        os.makedirs(STATE_FILE.parent, exist_ok=True)
        # atomic write
        tmp = STATE_FILE.with_suffix(".tmp")
        with open(tmp, "w", encoding="utf-8") as f:
            json.dump(state, f, indent=2)
        tmp.replace(STATE_FILE)
    except Exception as e:
        _log(f"save_state err: {e}")


def _fetch_pct_change(symbol, hours):
    """Fetch last N hours of 1H candles and compute % change."""
    try:
        n_candles = hours + 1
        r = requests.get(
            f"{BYBIT_BASE}/v5/market/kline",
            params={"category": "linear", "symbol": symbol, "interval": "60", "limit": n_candles},
            timeout=10,
        )
        data = r.json()
        candles = data.get("result", {}).get("list", [])
        if len(candles) < 2:
            return None
        # candles: [ts_ms, open, high, low, close, volume, ...]
        # Bybit returns DESC order (newest first)
        first_open = float(candles[-1][1])  # oldest
        last_close = float(candles[0][4])   # newest
        return (last_close - first_open) / first_open
    except Exception as e:
        _log(f"fetch_pct_change {symbol} {hours}h err: {e}")
        return None


def check_and_update():
    """Check regime, update state. Returns updated state."""
    state = _load_state()
    now = time.time()
    state["last_check"] = now

    changes = {}
    for sym in SYMBOLS:
        chg_4h = _fetch_pct_change(sym, 4)
        chg_24h = _fetch_pct_change(sym, 24)
        changes[sym] = {"4h": chg_4h, "24h": chg_24h}
        state["last_4h_chg"][sym] = chg_4h
        state["last_24h_chg"][sym] = chg_24h

    # Detect panic
    panic = False
    reason = []
    panic_until_existing = state.get("panic_until", 0)

    for sym, chg in changes.items():
        if chg["4h"] is not None and chg["4h"] < PANIC_4H_THRESHOLD:
            panic = True
            reason.append(f"{sym} 4h={chg['4h']*100:.2f}% < -2.5%")
            panic_until_existing = max(panic_until_existing, now + PANIC_4H_DURATION)
        if chg["24h"] is not None and chg["24h"] < PANIC_24H_THRESHOLD:
            panic = True
            reason.append(f"{sym} 24h={chg['24h']*100:.2f}% < -5%")
            panic_until_existing = max(panic_until_existing, now + PANIC_24H_DURATION)

    state["panic_until"] = panic_until_existing
    if panic:
        state["panic_reason"] = "; ".join(reason)
        _log(f"PANIC DETECTED: {state['panic_reason']} -> until {datetime.fromtimestamp(panic_until_existing, tz=timezone.utc).isoformat()}")
    else:
        # clear if past
        if state["panic_until"] > 0 and now > state["panic_until"]:
            state["panic_until"] = 0
            state.pop("panic_reason", None)

    _save_state(state)
    return state


def is_panic():
    """Returns True if currently in panic mode (no new entries allowed)."""
    state = _load_state()
    now = time.time()
    if state.get("panic_until", 0) > now:
        return True
    return False


def get_state():
    return _load_state()


if __name__ == "__main__":
    state = check_and_update()
    print(json.dumps(state, indent=2, ensure_ascii=False))
    print(f"\nIS_PANIC: {is_panic()}")
