from __future__ import annotations

import json
from pathlib import Path

from src.signals.tradingview import (
    TradingViewWebhookConfig,
    handle_tradingview_payload,
    normalize_tradingview_payload,
)


def _payload(**overrides):
    payload = {
        "source": "tradingview",
        "strategy": "gaussian_channel_v1",
        "symbol": "BTCUSDT",
        "side": "long",
        "action": "entry",
        "timeframe": "1h",
        "price": "61234.5",
        "timestamp": "2026-06-28T18:00:00Z",
        "signal_id": "tv-btc-1h-20260628T1800",
    }
    payload.update(overrides)
    return payload


def test_normalize_tradingview_payload_maps_symbol_and_defaults_to_paper_signal():
    signal = normalize_tradingview_payload(
        _payload(symbol="BTCUSDT.P"),
        allowed_strategies={"gaussian_channel_v1"},
        allowed_coins={"BTC", "ETH"},
    )

    assert signal.coin == "BTC"
    assert signal.strategy_id == "gaussian_channel_v1"
    assert signal.side == "long"
    assert signal.action == "entry"
    assert signal.execution_mode == "paper_signal"
    assert signal.live_order_allowed is False


def test_invalid_strategy_is_rejected_without_signal_journal_but_with_rejection_audit(tmp_path):
    cfg = TradingViewWebhookConfig(
        runtime_dir=tmp_path,
        secret="expected-secret",
        allowed_strategies={"squeeze_breakout_1h"},
        allowed_coins={"BTC"},
    )

    result = handle_tradingview_payload(
        _payload(strategy="unknown_strategy", secret="payload-secret-should-not-be-written"),
        headers={"X-CTB-Webhook-Secret": "expected-secret"},
        config=cfg,
    )

    assert result["accepted"] is False
    assert result["reason"] == "strategy_not_allowed"
    assert not (tmp_path / "signals" / "signal_journal.jsonl").exists()
    reject_journal = tmp_path / "signals" / "rejected_signal_journal.jsonl"
    row = json.loads(reject_journal.read_text(encoding="utf-8").splitlines()[0])
    assert row["reason"] == "strategy_not_allowed"
    assert row["source"] == "tradingview"
    assert row["live_order_allowed"] is False
    assert "secret" not in json.dumps(row).lower()


def test_webhook_requires_secret_and_never_allows_live_order(tmp_path):
    cfg = TradingViewWebhookConfig(
        runtime_dir=tmp_path,
        secret="expected-secret",
        allowed_strategies={"gaussian_channel_v1"},
        allowed_coins={"BTC"},
    )

    result = handle_tradingview_payload(_payload(), headers={}, config=cfg)

    assert result["accepted"] is False
    assert result["reason"] == "unauthorized"
    assert result["live_order_allowed"] is False
    assert not (tmp_path / "signals" / "rejected_signal_journal.jsonl").exists()


def test_accepted_webhook_appends_sanitized_signal_journal(tmp_path):
    cfg = TradingViewWebhookConfig(
        runtime_dir=tmp_path,
        secret="expected-secret",
        allowed_strategies={"gaussian_channel_v1"},
        allowed_coins={"BTC"},
    )

    result = handle_tradingview_payload(
        _payload(secret="payload-secret-should-not-be-written"),
        headers={"X-CTB-Webhook-Secret": "expected-secret"},
        config=cfg,
    )

    assert result["accepted"] is True
    assert result["coin"] == "BTC"
    assert result["execution_mode"] == "paper_signal"
    assert result["live_order_allowed"] is False

    journal = tmp_path / "signals" / "signal_journal.jsonl"
    rows = [json.loads(line) for line in journal.read_text(encoding="utf-8").splitlines()]
    assert len(rows) == 1
    row = rows[0]
    assert row["source"] == "tradingview"
    assert row["coin"] == "BTC"
    assert row["strategy_id"] == "gaussian_channel_v1"
    assert row["execution_mode"] == "paper_signal"
    assert row["live_order_allowed"] is False
    assert "secret" not in json.dumps(row).lower()


def test_duplicate_signal_id_is_rejected(tmp_path):
    cfg = TradingViewWebhookConfig(
        runtime_dir=tmp_path,
        secret="expected-secret",
        allowed_strategies={"gaussian_channel_v1"},
        allowed_coins={"BTC"},
    )
    headers = {"X-CTB-Webhook-Secret": "expected-secret"}

    first = handle_tradingview_payload(_payload(), headers=headers, config=cfg)
    second = handle_tradingview_payload(_payload(), headers=headers, config=cfg)

    assert first["accepted"] is True
    assert second["accepted"] is False
    assert second["reason"] == "duplicate_signal"


def test_cli_ingests_payload_file(tmp_path):
    payload_path = tmp_path / "payload.json"
    payload_path.write_text(json.dumps(_payload()), encoding="utf-8")
    secret_path = tmp_path / "secret.txt"
    secret_path.write_text("expected-secret\n", encoding="utf-8")

    from src.tools.tradingview_webhook import main

    exit_code = main([
        "--payload-file", str(payload_path),
        "--runtime-dir", str(tmp_path / "runtime"),
        "--secret-file", str(secret_path),
        "--header-secret", "expected-secret",
        "--allowed-strategy", "gaussian_channel_v1",
        "--allowed-coin", "BTC",
        "--json",
    ])

    assert exit_code == 0
    assert (tmp_path / "runtime" / "signals" / "signal_journal.jsonl").exists()
