# app/tests/unit/market_data/acquisition/adapters/dzengi/test_models.py

from __future__ import annotations

from dataclasses import FrozenInstanceError

import pytest

from src.market_data.acquisition.adapters.dzengi.models import (
    DzengiExchangeInfoPayload,
    DzengiExchangeInfoResponse,
    DzengiExchangeInfoSymbol,
    DzengiLotSizeFilter,
    DzengiMinNotionalFilter,
    DzengiRateLimit,
    DzengiUnknownFilter,
)


def test_exchange_info_response_stores_complete_raw_contract() -> None:
    lot_size = DzengiLotSizeFilter(
        filter_type="LOT_SIZE",
        min_qty="0.001",
        max_qty="1000",
        step_size="0.001",
    )
    min_notional = DzengiMinNotionalFilter(
        filter_type="MIN_NOTIONAL",
        min_notional="2",
    )

    symbol = DzengiExchangeInfoSymbol(
        symbol="ETH/EUR_LEVERAGE",
        name="ETH/EUR",
        status="TRADING",
        asset_type="CRYPTOCURRENCY",
        base_asset="ETH",
        base_asset_precision=3,
        quote_asset="EUR",
        quote_asset_id="EUR_LEVERAGE",
        quote_precision=3,
        order_types=("LIMIT", "MARKET", "STOP"),
        filters=(lot_size, min_notional),
        market_modes=("REGULAR",),
        market_type="LEVERAGE",
        country="",
        sector="",
        industry="",
        trading_hours="UTC; Mon - 21:00, 21:05 -",
        tick_size=0.01,
        tick_value=18.3415,
        trading_fee=0.06,
        exchange_fee=None,
        long_rate=-0.01,
        short_rate=0.01,
        swap_charge_interval=480,
        min_sl_gap=0,
        max_sl_gap=50.0,
        min_tp_gap=0,
        max_tp_gap=50.0,
    )

    payload = DzengiExchangeInfoPayload(
        timezone="UTC",
        server_time=1783537921471,
        rate_limits=(
            DzengiRateLimit(
                interval="MINUTE",
                interval_num=1,
                limit=1200,
                rate_limit_type="REQUEST_WEIGHT",
            ),
        ),
        exchange_filters=(),
        symbols=(symbol,),
    )

    response = DzengiExchangeInfoResponse(payload=payload)

    assert response.status is None
    assert response.correlation_id is None

    assert response.payload.timezone == "UTC"
    assert response.payload.server_time == 1783537921471
    assert len(response.payload.symbols) == 1

    parsed_symbol = response.payload.symbols[0]

    assert parsed_symbol.symbol == "ETH/EUR_LEVERAGE"
    assert parsed_symbol.filters == (lot_size, min_notional)
    assert parsed_symbol.tick_size == 0.01
    assert parsed_symbol.trading_fee == 0.06
    assert parsed_symbol.exchange_fee is None


def test_exchange_info_response_supports_wrapped_api_metadata() -> None:
    payload = DzengiExchangeInfoPayload(
        timezone="UTC",
        server_time=1628193845310,
        rate_limits=(),
        exchange_filters=(),
        symbols=(),
    )

    response = DzengiExchangeInfoResponse(
        status="OK",
        correlation_id="2",
        payload=payload,
    )

    assert response.status == "OK"
    assert response.correlation_id == "2"
    assert response.payload.symbols == ()


def test_exchange_info_symbol_accepts_optional_transport_fields() -> None:
    symbol = DzengiExchangeInfoSymbol(
        symbol="TUI1.",
        name="TUI - EUR",
        status="TRADING",
        asset_type="EQUITY",
        base_asset="TUI1.",
        base_asset_precision=3,
        quote_asset="EUR",
        quote_asset_id="EUR_LEVERAGE",
        quote_precision=3,
        order_types=("LIMIT", "MARKET", "STOP"),
        filters=(
            DzengiLotSizeFilter(
                filter_type="LOT_SIZE",
                min_qty="0.1",
                max_qty="33000",
                step_size="0.1",
            ),
        ),
        market_modes=("REGULAR",),
        market_type="LEVERAGE",
        country="DE",
        sector="Cyclical Consumer Goods & Services",
        industry="Leisure & Recreation",
        trading_hours="UTC; Mon 07:00 - 15:30",
        tick_size=0.005,
        tick_value=None,
        trading_fee=0,
        exchange_fee=None,
        long_rate=-0.0165933,
        short_rate=-0.0056289,
        swap_charge_interval=1440,
        min_sl_gap=0,
        max_sl_gap=30.0,
        min_tp_gap=0,
        max_tp_gap=30.0,
    )

    assert symbol.tick_value is None
    assert symbol.exchange_fee is None
    assert len(symbol.filters) == 1


def test_unknown_filter_preserves_unrecognized_scalar_fields() -> None:
    unknown_filter = DzengiUnknownFilter(
        filter_type="FUTURE_FILTER",
        fields=(
            ("enabled", True),
            ("limit", 10),
            ("mode", "STRICT"),
            ("description", None),
        ),
    )

    assert unknown_filter.filter_type == "FUTURE_FILTER"
    assert unknown_filter.fields == (
        ("enabled", True),
        ("limit", 10),
        ("mode", "STRICT"),
        ("description", None),
    )


def test_raw_models_use_immutable_sequences() -> None:
    payload = DzengiExchangeInfoPayload(
        timezone=None,
        server_time=None,
        rate_limits=(),
        exchange_filters=(),
        symbols=(),
    )

    assert isinstance(payload.rate_limits, tuple)
    assert isinstance(payload.exchange_filters, tuple)
    assert isinstance(payload.symbols, tuple)


def test_raw_models_are_immutable() -> None:
    payload = DzengiExchangeInfoPayload(
        timezone="UTC",
        server_time=1783537921471,
        rate_limits=(),
        exchange_filters=(),
        symbols=(),
    )

    response = DzengiExchangeInfoResponse(payload=payload)

    with pytest.raises(FrozenInstanceError):
        response.status = "OK"  # type: ignore[misc]