# app/tests/unit/market_data/acquisition/models/test_instrument.py

from __future__ import annotations

from dataclasses import FrozenInstanceError
from decimal import Decimal

import pytest

from src.market_data.acquisition.models.instrument import Instrument


def test_instrument_stores_complete_reference_data() -> None:
    instrument = Instrument(
        symbol="ETH/EUR_LEVERAGE",
        name="ETH/EUR",
        status="TRADING",
        base_asset="ETH",
        quote_asset="EUR",
        asset_type="CRYPTOCURRENCY",
        market_type="LEVERAGE",
        market_modes=("REGULAR",),
        order_types=("LIMIT", "MARKET", "STOP"),
        base_asset_precision=3,
        quote_asset_precision=3,
        tick_size=Decimal("0.01"),
        tick_value=Decimal("18.3415"),
        step_size=Decimal("0.001"),
        min_qty=Decimal("0.001"),
        max_qty=Decimal("1000"),
        min_notional=Decimal("2"),
        country=None,
        sector=None,
        industry=None,
        trading_hours=(
            "UTC; Mon - 21:00, 21:05 -; "
            "Tue - 21:00, 21:05 -"
        ),
    )

    assert instrument.symbol == "ETH/EUR_LEVERAGE"
    assert instrument.name == "ETH/EUR"
    assert instrument.status == "TRADING"

    assert instrument.base_asset == "ETH"
    assert instrument.quote_asset == "EUR"
    assert instrument.asset_type == "CRYPTOCURRENCY"

    assert instrument.market_type == "LEVERAGE"
    assert instrument.market_modes == ("REGULAR",)
    assert instrument.order_types == ("LIMIT", "MARKET", "STOP")

    assert instrument.base_asset_precision == 3
    assert instrument.quote_asset_precision == 3

    assert instrument.tick_size == Decimal("0.01")
    assert instrument.tick_value == Decimal("18.3415")

    assert instrument.step_size == Decimal("0.001")
    assert instrument.min_qty == Decimal("0.001")
    assert instrument.max_qty == Decimal("1000")
    assert instrument.min_notional == Decimal("2")

    assert instrument.country is None
    assert instrument.sector is None
    assert instrument.industry is None
    assert instrument.trading_hours is not None


def test_instrument_accepts_missing_optional_reference_values() -> None:
    instrument = Instrument(
        symbol="TEST/USD",
        name="Test instrument",
        status="BREAK",
        base_asset="TEST",
        quote_asset="USD",
        asset_type=None,
        market_type="SPOT",
        market_modes=(),
        order_types=(),
        base_asset_precision=None,
        quote_asset_precision=None,
        tick_size=None,
        tick_value=None,
        step_size=None,
        min_qty=None,
        max_qty=None,
        min_notional=None,
        country=None,
        sector=None,
        industry=None,
        trading_hours=None,
    )

    assert instrument.asset_type is None
    assert instrument.market_modes == ()
    assert instrument.order_types == ()
    assert instrument.base_asset_precision is None
    assert instrument.quote_asset_precision is None
    assert instrument.tick_size is None
    assert instrument.tick_value is None
    assert instrument.step_size is None
    assert instrument.min_qty is None
    assert instrument.max_qty is None
    assert instrument.min_notional is None
    assert instrument.trading_hours is None


def test_instrument_uses_immutable_sequences() -> None:
    instrument = Instrument(
        symbol="BTC/USD",
        name="BTC/USD",
        status="TRADING",
        base_asset="BTC",
        quote_asset="USD",
        asset_type="CRYPTOCURRENCY",
        market_type="SPOT",
        market_modes=("REGULAR",),
        order_types=("MARKET",),
        base_asset_precision=8,
        quote_asset_precision=2,
        tick_size=Decimal("0.01"),
        tick_value=None,
        step_size=Decimal("0.00000001"),
        min_qty=Decimal("0.00000001"),
        max_qty=Decimal("100"),
        min_notional=Decimal("1"),
        country=None,
        sector=None,
        industry=None,
        trading_hours=None,
    )

    assert isinstance(instrument.market_modes, tuple)
    assert isinstance(instrument.order_types, tuple)


def test_instrument_is_immutable() -> None:
    instrument = Instrument(
        symbol="BTC/USD",
        name="BTC/USD",
        status="TRADING",
        base_asset="BTC",
        quote_asset="USD",
        asset_type="CRYPTOCURRENCY",
        market_type="SPOT",
        market_modes=("REGULAR",),
        order_types=("MARKET",),
        base_asset_precision=8,
        quote_asset_precision=2,
        tick_size=Decimal("0.01"),
        tick_value=None,
        step_size=Decimal("0.00000001"),
        min_qty=Decimal("0.00000001"),
        max_qty=Decimal("100"),
        min_notional=Decimal("1"),
        country=None,
        sector=None,
        industry=None,
        trading_hours=None,
    )

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