from __future__ import annotations

from datetime import datetime, timedelta, timezone

import polars as pl

from uforia.config import get_config
from uforia.execution.live import BebopLiveClient
from uforia.execution.models import (
    ExecutionAccountConfig,
    ExecutionInstrumentType,
    ExecutionIntent,
    ExecutionOrderSide,
    ExecutionOrderType,
    ExecutionRequestMode,
    ExecutionVenue,
)
from uforia.execution.service import ExecutionService
from uforia.storage import DatasetName, DatasetStore


class _QuoteAwareLiveClient:
    def __init__(self) -> None:
        self.last_intent: ExecutionIntent | None = None

    def market_snapshots(self, asset=None):
        return []

    def account_snapshot(self, asset=None):
        return type(
            "Snapshot",
            (),
            {"balances": [], "positions": [], "orders": [], "fills": [], "health": None},
        )()

    def request_quote(self, request):
        raise NotImplementedError

    def place_order(self, intent):
        self.last_intent = intent
        return type(
            "Order",
            (),
            {
                "venue_order_id": "bebop-order-1",
                "message": "bebop executed",
                "payload": {"ok": True},
                "status": "accepted",
                "filled_size": 0.0,
                "remaining_size": 1.0,
                "avg_fill_price": None,
                "fill_events": [],
            },
        )()

    def cancel(self, request):
        raise NotImplementedError

    def cancel_all(self, request):
        raise NotImplementedError


def test_execution_service_hydrates_bebop_quote_payload(tmp_path, monkeypatch) -> None:
    config_dir = tmp_path / "config"
    config_dir.mkdir(parents=True, exist_ok=True)
    (config_dir / "execution_accounts.json").write_text(
        """
        [
          {
            "label": "bebop-main",
            "venue": "bebop",
            "environment": "mainnet",
            "wallet_address": "0x0000000000000000000000000000000000000000",
            "enabled_assets": ["BTC"],
            "enabled_symbols": ["BTC-USD"],
            "enabled": true,
            "kill_switch": false
          }
        ]
        """
    )
    monkeypatch.setenv("UFORIA_EXECUTION_ENABLED", "true")
    monkeypatch.setenv(
        "UFORIA_EXECUTION_ACCOUNTS_PATH",
        str(config_dir / "execution_accounts.json"),
    )
    monkeypatch.setenv("UFORIA_EXECUTION_KILL_SWITCH", "false")
    monkeypatch.setenv("UFORIA_EXECUTION_MAX_ORDER_NOTIONAL_USD", "200000")

    store = DatasetStore(tmp_path)
    ts = datetime(2026, 3, 12, 12, tzinfo=timezone.utc)
    store.write(
        DatasetName.EXECUTION_QUOTE_SNAPSHOT,
        pl.DataFrame(
            [
                {
                    "ts": ts,
                    "date": ts.date(),
                    "request_id": "req-1",
                    "quote_id": "quote-1",
                    "venue": "bebop",
                    "account": "bebop-main",
                    "asset": "BTC",
                    "symbol": "BTC-USD",
                    "side": "buy",
                    "price": 100000.0,
                    "size": 1.0,
                    "notional_usd": 100000.0,
                    "expires_at": ts + timedelta(minutes=5),
                    "route": "router",
                    "status": "accepted",
                    "payload": (
                        '{"tx":{"to":"0x0000000000000000000000000000000000000001",'
                        '"data":"0x","value":"0x0"}}'
                    ),
                    "quality_flag": "ok",
                }
            ]
        ),
    )

    fake_client = _QuoteAwareLiveClient()
    monkeypatch.setattr("uforia.execution.service.create_live_client", lambda **_: fake_client)

    service = ExecutionService(store, get_config())
    result = service.submit_order(
        ExecutionIntent(
            venue=ExecutionVenue.BEBOP,
            account="bebop-main",
            instrument_type=ExecutionInstrumentType.SPOT,
            asset="BTC",
            symbol="BTC-USD",
            side=ExecutionOrderSide.BUY,
            order_type=ExecutionOrderType.MARKET,
            size=1.0,
            mode=ExecutionRequestMode.LIVE,
            quote_id="quote-1",
        )
    )

    assert result.status.value == "accepted"
    assert fake_client.last_intent is not None
    assert "quote_payload" in fake_client.last_intent.metadata


def test_bebop_live_client_self_execute_broadcasts_bundle(tmp_path, monkeypatch) -> None:
    monkeypatch.setenv(
        "UFORIA_BEBOP_PRIVATE_KEY",
        "0x59c6995e998f97a5a0044966f0945382d7d8f2bb6f02a5ab3f7d8b7d7f7e4d8b",
    )
    monkeypatch.setenv("UFORIA_BEBOP_RPC_URL", "http://rpc.local")

    rpc_calls: list[tuple[str, list[object]]] = []

    def fake_rpc_call(rpc_url: str, method: str, params: list[object]) -> object:
        rpc_calls.append((method, params))
        if method == "eth_getTransactionCount":
            return hex(7)
        if method == "eth_estimateGas":
            return hex(21000)
        if method == "eth_gasPrice":
            return hex(1_000_000_000)
        if method == "eth_sendRawTransaction":
            return "0xabc123"
        raise AssertionError(method)

    monkeypatch.setattr("uforia.execution.live._rpc_call", fake_rpc_call)

    client = BebopLiveClient(
        config=get_config(),
        account=ExecutionAccountConfig(
            label="bebop-main",
            venue=ExecutionVenue.BEBOP,
            environment="mainnet",
            wallet_address="0x0000000000000000000000000000000000000000",
            private_key_env="UFORIA_BEBOP_PRIVATE_KEY",
            rpc_url_env="UFORIA_BEBOP_RPC_URL",
            enabled_assets=["BTC"],
            enabled_symbols=["BTC-USD"],
            metadata={"execution_mode": "self_execute", "chain_id": 1},
        ),
    )

    result = client.place_order(
        ExecutionIntent(
            venue=ExecutionVenue.BEBOP,
            account="bebop-main",
            instrument_type=ExecutionInstrumentType.SPOT,
            asset="BTC",
            symbol="BTC-USD",
            side=ExecutionOrderSide.BUY,
            order_type=ExecutionOrderType.MARKET,
            size=1.0,
            mode=ExecutionRequestMode.LIVE,
            quote_id="quote-1",
            metadata={
                "quote_payload": {
                    "tx": {
                        "to": "0x0000000000000000000000000000000000000001",
                        "data": "0x",
                        "value": "0x0",
                    }
                }
            },
        )
    )

    assert result.status.value == "accepted"
    assert result.venue_order_id == "0xabc123"
    assert any(method == "eth_sendRawTransaction" for method, _ in rpc_calls)
