from __future__ import annotations

import json
import threading
import urllib.error
import urllib.request
from pathlib import Path

from src.tools.tradingview_webhook import main as cli_main


def test_http_server_accepts_post_and_journals_paper_signal(tmp_path):
    from src.tools.tradingview_webhook_server import build_parser, make_server

    secret_file = tmp_path / "secret.txt"
    secret_file.write_text("expected-secret\n", encoding="utf-8")
    args = build_parser().parse_args([
        "--host", "127.0.0.1",
        "--port", "0",
        "--runtime-dir", str(tmp_path / "runtime"),
        "--secret-file", str(secret_file),
        "--allowed-strategy", "gaussian_channel_v1",
        "--allowed-coin", "BTC",
    ])
    server = make_server(args)
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()
    try:
        port = server.server_address[1]
        payload = json.dumps({
            "source": "tradingview",
            "strategy": "gaussian_channel_v1",
            "symbol": "BTCUSDT.P",
            "side": "long",
            "action": "entry",
            "timeframe": "1h",
            "price": "61234.5",
            "timestamp": "2026-06-28T18:00:00Z",
            "signal_id": "http-smoke-1",
        }).encode("utf-8")
        req = urllib.request.Request(
            f"http://127.0.0.1:{port}/webhook/tradingview",
            data=payload,
            method="POST",
            headers={"Content-Type": "application/json", "X-CTB-Webhook-Secret": "expected-secret"},
        )
        with urllib.request.urlopen(req, timeout=5) as resp:
            body = json.loads(resp.read().decode("utf-8"))
            assert resp.status == 200
        assert body["accepted"] is True
        assert body["live_order_allowed"] is False
        journal = tmp_path / "runtime" / "signals" / "signal_journal.jsonl"
        row = json.loads(journal.read_text(encoding="utf-8").splitlines()[0])
        assert row["execution_mode"] == "paper_signal"
        assert row["mainnet_signed_action"] is False
    finally:
        server.shutdown()
        server.server_close()


def test_http_server_rejects_wrong_path_without_journal(tmp_path):
    from src.tools.tradingview_webhook_server import build_parser, make_server

    secret_file = tmp_path / "secret.txt"
    secret_file.write_text("expected-secret\n", encoding="utf-8")
    args = build_parser().parse_args([
        "--host", "127.0.0.1",
        "--port", "0",
        "--runtime-dir", str(tmp_path / "runtime"),
        "--secret-file", str(secret_file),
        "--allowed-strategy", "gaussian_channel_v1",
        "--allowed-coin", "BTC",
    ])
    server = make_server(args)
    thread = threading.Thread(target=server.serve_forever, daemon=True)
    thread.start()
    try:
        port = server.server_address[1]
        req = urllib.request.Request(
            f"http://127.0.0.1:{port}/wrong",
            data=b"{}",
            method="POST",
            headers={"Content-Type": "application/json", "X-CTB-Webhook-Secret": "expected-secret"},
        )
        try:
            urllib.request.urlopen(req, timeout=5)
            raise AssertionError("expected HTTPError")
        except urllib.error.HTTPError as exc:
            assert exc.code == 404
        assert not (tmp_path / "runtime" / "signals" / "signal_journal.jsonl").exists()
    finally:
        server.shutdown()
        server.server_close()


def test_cli_still_returns_nonzero_for_unauthorized_payload(tmp_path):
    payload_path = tmp_path / "payload.json"
    payload_path.write_text(json.dumps({
        "source": "tradingview",
        "strategy": "gaussian_channel_v1",
        "symbol": "BTCUSDT",
        "side": "long",
        "action": "entry",
        "timeframe": "1h",
        "price": "1",
        "timestamp": "2026-06-28T18:00:00Z",
        "signal_id": "unauth-1",
    }), encoding="utf-8")
    secret_path = tmp_path / "secret.txt"
    secret_path.write_text("expected-secret\n", encoding="utf-8")

    code = cli_main([
        "--payload-file", str(payload_path),
        "--runtime-dir", str(tmp_path / "runtime"),
        "--secret-file", str(secret_path),
        "--header-secret", "wrong-secret",
        "--allowed-strategy", "gaussian_channel_v1",
        "--allowed-coin", "BTC",
        "--json",
    ])
    assert code == 2
    assert not (tmp_path / "runtime" / "signals" / "signal_journal.jsonl").exists()
