from __future__ import annotations

import json
from datetime import datetime, timezone, timedelta
from pathlib import Path

from src.research.tradingview_context import classify_tradingview_impulse, load_tradingview_latest, normalize_tradingview_context, rank_tradeable_coins, tradingview_blockers
from src.tools.tradingview_coin_selector import build_selection_report


def test_tradingview_context_whitelists_and_blocks_conflicted_long():
    now = datetime(2026, 7, 4, 22, 0, tzinfo=timezone.utc)
    ctx = normalize_tradingview_context({
        "coin": "SOL",
        "symbol": "SOLUSDT",
        "ts": (now - timedelta(minutes=5)).isoformat(),
        "bias": "bearish",
        "confidence": "0.82",
        "trend_alignment": "conflict",
        "volume_state": "weak",
        "volatility_state": "normal",
        "no_trade_reasons": ["higher_tf_down", {"ignored": True}],
        "free_text_command": "buy now",
        "research_only": True,
        "source": "tradingview_mcp",
    }, now=now)

    blockers = tradingview_blockers(ctx, side="long")

    assert ctx.coin == "SOL"
    assert ctx.confidence == ctx.confidence.__class__("0.82")
    assert "tv_bias_bearish" in blockers
    assert "tv_mtf_conflict" in blockers
    assert "tv_volume_not_confirmed" in blockers
    assert "tv_no_trade_higher_tf_down" in blockers


def test_load_tradingview_latest_and_rank_prefers_evidence_then_context(tmp_path):
    now = datetime(2026, 7, 4, 22, 0, tzinfo=timezone.utc)
    tv = tmp_path / "tradingview_latest.json"
    tv.write_text(json.dumps({"coins": [
        {"coin": "BTC", "symbol": "BTCUSDT", "ts": now.isoformat(), "bias": "bearish", "trend_alignment": "conflict", "volume_state": "normal", "confidence": 0.9},
        {"coin": "ETH", "symbol": "ETHUSDT", "ts": now.isoformat(), "bias": "bullish", "trend_alignment": "aligned", "volume_state": "breakout", "confidence": 0.8},
    ]}))
    contexts = load_tradingview_latest(tv, now=now)
    ranked = rank_tradeable_coins(candidate_coins=["BTC", "ETH", "SOL"], paper_pnl_by_coin={"BTC": 1.0, "ETH": 0.4, "SOL": 0.2}, tv_contexts=contexts)

    assert set(contexts) == {"BTC", "ETH"}
    assert ranked[0] == "ETH"  # BTC had more raw PnL, but TV conflict demotes it.


def test_tradingview_impulse_classifies_buy_opportunity_without_live_permission():
    now = datetime(2026, 7, 4, 22, 0, tzinfo=timezone.utc)
    ctx = normalize_tradingview_context({
        "coin": "BTC",
        "symbol": "BTCUSDT",
        "ts": (now - timedelta(minutes=3)).isoformat(),
        "bias": "bullish",
        "confidence": "0.78",
        "trend_alignment": "aligned",
        "volume_state": "breakout",
        "volatility_state": "squeeze",
        "research_only": True,
        "source": "tradingview_mcp",
    }, now=now)

    impulse = classify_tradingview_impulse(ctx, side="long", max_age_seconds=3600)

    assert impulse["category"] == "buy_opportunity"
    assert impulse["action"] == "paper_candidate_if_other_gates_pass"
    assert impulse["live_order_allowed"] is False
    assert impulse["mainnet_signed_action"] is False


def test_tradingview_impulse_demotes_bearish_or_no_trade_context():
    now = datetime(2026, 7, 4, 22, 0, tzinfo=timezone.utc)
    ctx = normalize_tradingview_context({
        "coin": "ETH",
        "symbol": "ETHUSDT",
        "ts": (now - timedelta(minutes=3)).isoformat(),
        "bias": "bearish",
        "confidence": "0.80",
        "trend_alignment": "conflict",
        "volume_state": "normal",
        "no_trade_reasons": ["higher_tf_down"],
        "research_only": True,
        "source": "tradingview_mcp",
    }, now=now)

    impulse = classify_tradingview_impulse(ctx, side="long", max_age_seconds=3600)

    assert impulse["category"] == "avoid_long"
    assert "tv_bias_bearish" in impulse["reasons"]
    assert "tv_no_trade_higher_tf_down" in impulse["reasons"]


def test_coin_selector_outputs_readonly_runtime_report(tmp_path):
    runtime = tmp_path / "runtime" / "experiments"
    anti = runtime / "candidate_v76_fee_aware_anti_chase"
    anti.mkdir(parents=True)
    (anti / "trade_journal.jsonl").write_text(json.dumps({"event": "exit", "coin": "SOL", "net_pnl_usd": "1.5"}) + "\n")
    tv = tmp_path / "runtime" / "research" / "tradingview_latest.json"
    tv.parent.mkdir(parents=True)
    tv.write_text(json.dumps({"coins": [{"coin": "SOL", "symbol": "SOLUSDT", "ts": datetime.now(timezone.utc).isoformat(), "bias": "bullish", "trend_alignment": "aligned", "volume_state": "normal", "research_only": True, "source": "tradingview_mcp"}]}))

    report = build_selection_report(candidates=["BTC", "SOL"], runtime_root=runtime, tv_path=tv)

    assert report["research_only"] is True
    assert report["live_order_allowed"] is False
    assert report["mainnet_signed_action"] is False
    assert report["selected_order"][0] == "SOL"
    assert report["tradingview_context"]["SOL"]["source"] == "tradingview_mcp"
