"""期权交割账单镜像 + 期期开仓账本。"""

from __future__ import annotations

from types import SimpleNamespace

from app.live.option_settle import (
    OptionSettlement,
    fetch_option_settlement,
    settlement_to_fill,
)


def test_settlement_to_fill_zero_when_not_found() -> None:
    st = OptionSettlement(found=False)
    assert settlement_to_fill(st, qty_eth=2.0) == (0.0, 0.0, 0.0)


def test_okx_settlement_from_exercise_bills() -> None:
    class _C:
        def get_option_settlement_bills(self, inst_id, *, begin_ms, end_ms=None):
            return [
                {
                    "subType": "170",
                    "type": "3",
                    "ts": str(begin_ms + 1000),
                    "balChg": "50.0",
                    "fee": "-0.5",
                    "ccy": "USDT",
                }
            ]

    st = fetch_option_settlement(
        _C(),
        exchange="okx",
        option_inst_id="ETH-USDT-260808-2000-C",
        qty_eth=2.0,
        begin_ms=1_700_000_000_000,
    )
    assert st.found
    assert abs(st.cash - 50.0) < 1e-9
    px, fee, notional = settlement_to_fill(st, qty_eth=2.0)
    assert fee == 0.5
    assert abs(notional - 50.5) < 1e-9
    assert abs(px - 25.25) < 1e-9


def test_bn_settlement_from_exercise_record() -> None:
    class _C:
        def get_option_exercise_records(self, symbol, *, begin_ms, end_ms=None):
            return [
                {
                    "symbol": symbol,
                    "amount": "40",
                    "fee": "0.2",
                    "currency": "USDT",
                    "quantity": "2",
                }
            ]

    st = fetch_option_settlement(
        _C(),
        exchange="binance",
        option_inst_id="ETH-260808-2000-C",
        qty_eth=2.0,
        begin_ms=1,
    )
    assert st.found
    assert abs(st.cash - 39.8) < 1e-9
    px, fee, notional = settlement_to_fill(st, qty_eth=2.0)
    assert abs(notional - 40.0) < 1e-9
    assert abs(px - 20.0) < 1e-9
    assert abs(fee - 0.2) < 1e-9


def test_okx_otm_expiry_bill_found_zero_cash() -> None:
    class _C:
        def get_option_settlement_bills(self, *_a, **_k):
            return [
                {
                    "subType": "172",
                    "type": "3",
                    "ts": "1700000001000",
                    "balChg": "0",
                    "fee": "0",
                    "ccy": "USDT",
                }
            ]

    st = fetch_option_settlement(
        _C(),
        exchange="okx",
        option_inst_id="ETH-OPT",
        qty_eth=1.0,
        begin_ms=1_700_000_000_000,
    )
    assert st.found
    assert st.cash == 0.0
    assert settlement_to_fill(st, qty_eth=1.0)[0] == 0.0


def test_oo_open_applies_ledger_cash(monkeypatch, tmp_path) -> None:
    monkeypatch.setenv("MODE", "LIVE")
    from app.config import get_settings

    get_settings.cache_clear()
    from app.live.executor import OkxLiveExecutor
    from app.models.db import Database

    db = Database(tmp_path / "oo.db")
    ex = OkxLiveExecutor(db)
    monkeypatch.setattr(ex, "_guard_live", lambda: None)
    monkeypatch.setattr(
        "app.live.executor.claim_open_slot", lambda _db: (True, "ok")
    )
    monkeypatch.setattr(
        "app.live.executor.assert_safe_to_open_live", lambda _e: (True, "ok")
    )
    monkeypatch.setattr(
        "app.live.executor.stamp_opening_intent", lambda *_a, **_k: None
    )
    monkeypatch.setattr(
        "app.live.executor.release_open_slot_if_opening", lambda *_a, **_k: None
    )
    monkeypatch.setattr(ex, "_ct_mult", lambda *_a, **_k: 0.01)

    class _C:
        def place_market(self, *, inst_id, side, sz, **_k):
            return SimpleNamespace(
                avg_px=10.0 if "C" in inst_id or "call" in inst_id.lower() or inst_id.endswith("-C") or "CALL" in inst_id
                else 8.0,
                fee=0.1,
                sz=float(sz),
            )

    # simpler fixed fills
    fills = [
        SimpleNamespace(avg_px=10.0, fee=0.1, sz=100.0),
        SimpleNamespace(avg_px=8.0, fee=0.05, sz=100.0),
    ]

    def place(**_k):
        return fills.pop(0)

    monkeypatch.setattr(ex, "_client", lambda: SimpleNamespace(place_market=place))
    monkeypatch.setattr(
        ex.ledger,
        "get_setting_float",
        lambda k, d=0: 1.0 if "qty" in k else d,
    )

    before = float(ex.ledger.snapshot()["available"])
    r = ex.open_oo_group(
        group_id="G-oo1",
        call_inst_id="ETH-CALL",
        put_inst_id="ETH-PUT",
        call_strike=2000.0,
        put_strike=1900.0,
        entry_index_px=1950.0,
        expiry_ymd="260810",
    )
    assert r.ok, r.detail
    after = float(ex.ledger.snapshot()["available"])
    # call 10*1 +0.1 + put 8*1 +0.05 = 18.15
    assert before - after > 18.0
    db.close()
    get_settings.cache_clear()
