import time, json, random
from pathlib import Path
from typing import List, Dict
from .data_fetch import get_price, get_intraday_metrics
from .scoring import compute_score
from .filters import apply_filters
from ..core.config import DATA_DIR, SCORE_MIN, RVOL_MIN, ATR_MIN, ATR_MAX, CRV_MIN

WATCHLIST_PATH = DATA_DIR / "watchlist.json"
ACTIVE_SIGNALS_PATH = DATA_DIR / "active_signals.json"
SCANS_PATH = DATA_DIR / "scans.json"

def load_watchlist() -> List[str]:
    if not WATCHLIST_PATH.exists():
        return []
    return json.loads(WATCHLIST_PATH.read_text())

def save_active_signals(signals: List[Dict]):
    ACTIVE_SIGNALS_PATH.write_text(json.dumps(signals, indent=2))

def load_active_signals() -> List[Dict]:
    if not ACTIVE_SIGNALS_PATH.exists():
        return []
    return json.loads(ACTIVE_SIGNALS_PATH.read_text())

def append_scan(meta: Dict):
    scans = []
    if SCANS_PATH.exists():
        try:
            raw = SCANS_PATH.read_text().strip()
            if raw:
                scans = json.loads(raw)
                # Falls versehentlich ein Objekt statt Liste gespeichert wurde
                if isinstance(scans, dict):
                    scans = [scans]
        except Exception:
            # Fallback auf leere Liste, Datei war korrupt
            scans = []
    scans.insert(0, meta)
    SCANS_PATH.write_text(json.dumps(scans[:500], indent=2))

def synth_signal_row(ticker: str, live_filters: List[tuple]) -> Dict:
    price = get_price(ticker)
    m = get_intraday_metrics(ticker)
    score = compute_score(m["rvol"], m["atrp"], m["trend"])
    row = {
        "ticker": ticker,
        "price": price,
        "rvol": m["rvol"],
        "atrp": m["atrp"],
        "trend": m["trend"],
        "score": score
    }
    # harte Vor-Filter
    if not (score >= SCORE_MIN and m["rvol"] >= RVOL_MIN and ATR_MIN <= m["atrp"] <= ATR_MAX):
        return {}
    # zusätzliche Live-Filter
    if live_filters and not apply_filters(row, live_filters):
        return {}

    direction = "LONG" if m["trend"] == "Aufwärts" else "SHORT"
    # einfache CRV/SL/TP-Synthese
    sl = round(price * (0.985 if direction=="LONG" else 1.015), 2)
    tp1 = round(price * (1.015 if direction=="LONG" else 0.985), 2)
    tp2 = round(price * (1.03 if direction=="LONG" else 0.97), 2)
    rr = abs((price - tp1) / (price - sl)) if (price - sl) != 0 else 2.0
    if rr < CRV_MIN:
        return {}
    winp = int(60 + min(20, max(0, (score - SCORE_MIN))))
    return {
        "ticker": ticker,
        "direction": direction,
        "price": price,
        "entry": price,
        "stop": sl,
        "tp1": tp1,
        "tp2": tp2,
        "crv": round(rr, 2),
        "win_chance": winp,
        "status": "Neu",
        "comment": f"Synth signal ({m['trend']}, RVOL {m['rvol']}, ATR% {m['atrp']})"
    }

def run_live_scan(live_filters: List[tuple]) -> Dict:
    start = time.time()
    watchlist = load_watchlist()
    signals = []
    for t in watchlist:
        s = synth_signal_row(t, live_filters)
        if s:
            signals.append(s)
    meta = {
        "at": time.strftime("%Y-%m-%d %H:%M:%S"),
        "kind": "live",
        "long_count": sum(1 for s in signals if s["direction"]=="LONG"),
        "short_count": sum(1 for s in signals if s["direction"]=="SHORT"),
        "status": "Erfolg",
        "duration_ms": int((time.time()-start)*1000)
    }
    append_scan(meta)
    save_active_signals(signals)
    return {"signals": signals, "meta": meta}

def run_full_scan() -> Dict:
    # für MVP analog live, aber später: großflächiges Universum & Top150-Auswahl
    return run_live_scan(live_filters=[])
