# app/tests/unit/market_data/acquisition/validation/test_websocket_ohlc_schema.py

from __future__ import annotations

from types import MappingProxyType

import pytest

from src.market_data.acquisition.exceptions import (
    CandleWebSocketSchemaError,
)
from src.market_data.acquisition.validation.schema import (
    ValidatedWebSocketOhlcDocument,
    validate_dzengi_websocket_ohlc_schema,
)


def _valid_document() -> dict[str, object]:
    return {
        "status": "OK",
        "destination": "ohlc.event",
        "payload": {
            "symbol": "BTC/USD_LEVERAGE",
            "interval": "1m",
            "type": "classic",
            "t": 1784224740000,
            "o": 63992.0,
            "h": 64032.55,
            "l": 63984.0,
            "c": 64032.55,
        },
    }


def test_validate_websocket_ohlc_schema_returns_immutable_document() -> None:
    result = validate_dzengi_websocket_ohlc_schema(
        _valid_document()
    )

    assert isinstance(result, ValidatedWebSocketOhlcDocument)
    assert isinstance(result.payload, MappingProxyType)

    assert result.status == "OK"
    assert result.destination == "ohlc.event"
    assert result.correlation_id is None

    assert result.payload == {
        "symbol": "BTC/USD_LEVERAGE",
        "interval": "1m",
        "type": "classic",
        "t": 1784224740000,
        "o": 63992.0,
        "h": 64032.55,
        "l": 63984.0,
        "c": 64032.55,
    }


def test_validate_websocket_ohlc_schema_preserves_correlation_id() -> None:
    document = _valid_document()
    document["correlationId"] = "correlation-1"

    result = validate_dzengi_websocket_ohlc_schema(document)

    assert result.correlation_id == "correlation-1"


def test_validate_websocket_ohlc_schema_copies_payload() -> None:
    document = _valid_document()
    payload = document["payload"]

    assert isinstance(payload, dict)

    result = validate_dzengi_websocket_ohlc_schema(document)

    payload["c"] = 1.0

    assert result.payload["c"] == 64032.55


def test_validate_websocket_ohlc_schema_rejects_non_mapping_root() -> None:
    with pytest.raises(
        CandleWebSocketSchemaError,
        match=r"\$ должен быть JSON-объектом",
    ):
        validate_dzengi_websocket_ohlc_schema([])


@pytest.mark.parametrize(
    "field_name",
    [
        "status",
        "destination",
        "payload",
    ],
)
def test_validate_websocket_ohlc_schema_rejects_missing_root_field(
    field_name: str,
) -> None:
    document = _valid_document()
    del document[field_name]

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=rf"\$\.{field_name} отсутствует",
    ):
        validate_dzengi_websocket_ohlc_schema(document)


def test_validate_websocket_ohlc_schema_rejects_non_mapping_payload() -> None:
    document = _valid_document()
    document["payload"] = []

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=r"\$\.payload должен быть JSON-объектом",
    ):
        validate_dzengi_websocket_ohlc_schema(document)


@pytest.mark.parametrize(
    "field_name",
    [
        "symbol",
        "interval",
        "type",
        "t",
        "o",
        "h",
        "l",
        "c",
    ],
)
def test_validate_websocket_ohlc_schema_rejects_missing_payload_field(
    field_name: str,
) -> None:
    document = _valid_document()
    payload = document["payload"]

    assert isinstance(payload, dict)

    del payload[field_name]

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=rf"обязательные поля WebSocket OHLC: {field_name}",
    ):
        validate_dzengi_websocket_ohlc_schema(document)


def test_validate_websocket_ohlc_schema_reports_all_missing_fields() -> None:
    document = _valid_document()
    payload = document["payload"]

    assert isinstance(payload, dict)

    del payload["symbol"]
    del payload["t"]
    del payload["c"]

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=r"symbol, t, c",
    ):
        validate_dzengi_websocket_ohlc_schema(document)


def test_validate_websocket_ohlc_schema_does_not_validate_values() -> None:
    document = _valid_document()
    payload = document["payload"]

    assert isinstance(payload, dict)

    document["status"] = 123
    document["destination"] = None

    payload["symbol"] = None
    payload["interval"] = []
    payload["type"] = "unknown"
    payload["t"] = -1
    payload["o"] = "NaN"
    payload["h"] = object()
    payload["l"] = False
    payload["c"] = None

    result = validate_dzengi_websocket_ohlc_schema(document)

    assert result.status == 123
    assert result.destination is None
    assert result.payload["type"] == "unknown"
    assert result.payload["t"] == -1


def test_validate_websocket_ohlc_schema_rejects_non_string_root_key() -> None:
    document = _valid_document()
    document[1] = "invalid"  # type: ignore[index]

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=r"\$ содержит нестроковый ключ",
    ):
        validate_dzengi_websocket_ohlc_schema(document)


def test_validate_websocket_ohlc_schema_rejects_non_string_payload_key() -> None:
    document = _valid_document()
    payload = document["payload"]

    assert isinstance(payload, dict)

    payload[1] = "invalid"  # type: ignore[index]

    with pytest.raises(
        CandleWebSocketSchemaError,
        match=r"\$\.payload содержит нестроковый ключ",
    ):
        validate_dzengi_websocket_ohlc_schema(document)