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

from __future__ import annotations

import pytest

from src.market_data.acquisition.adapters.dzengi.models import (
    DzengiKline,
    DzengiKlinesResponse,
)
from src.market_data.acquisition.exceptions import CandleValueError
from src.market_data.acquisition.validation.values import (
    validate_candles_values,
)


def _response(
    *,
    open_time: int = 1000,
    open_price: str | int | float = "100",
    high_price: str | int | float = "110",
    low_price: str | int | float = "90",
    close_price: str | int | float = "105",
    volume: str | int | float = "12.5",
) -> DzengiKlinesResponse:
    return DzengiKlinesResponse(
        items=(
            DzengiKline(
                open_time=open_time,
                open_price=open_price,
                high_price=high_price,
                low_price=low_price,
                close_price=close_price,
                volume=volume,
            ),
        )
    )


def test_validate_candles_values_accepts_valid_response() -> None:
    validate_candles_values(_response())


def test_validate_candles_values_accepts_zero_volume() -> None:
    validate_candles_values(_response(volume=0))


@pytest.mark.parametrize(
    ("field_name", "value"),
    [
        ("open_price", 0),
        ("high_price", 0),
        ("low_price", 0),
        ("close_price", 0),
        ("volume", -1),
    ],
)
def test_validate_candles_values_rejects_invalid_bounds(
    field_name: str,
    value: int,
) -> None:
    kwargs = {field_name: value}

    with pytest.raises(CandleValueError):
        validate_candles_values(_response(**kwargs))


@pytest.mark.parametrize(
    "value",
    ["NaN", "Infinity", "-Infinity"],
)
def test_validate_candles_values_rejects_non_finite_values(
    value: str,
) -> None:
    with pytest.raises(CandleValueError):
        validate_candles_values(_response(open_price=value))


@pytest.mark.parametrize(
    "open_time",
    [0, -1],
)
def test_validate_candles_values_rejects_invalid_open_time(
    open_time: int,
) -> None:
    with pytest.raises(
        CandleValueError,
        match=r"\$\.candles\[0\]\.openTime",
    ):
        validate_candles_values(_response(open_time=open_time))


@pytest.mark.parametrize(
    "response",
    [
        _response(high_price="99"),
        _response(low_price="101"),
        _response(high_price="80", low_price="90"),
    ],
)
def test_validate_candles_values_rejects_invalid_ohlc(
    response: DzengiKlinesResponse,
) -> None:
    with pytest.raises(CandleValueError):
        validate_candles_values(response)


def test_validate_candles_values_accepts_empty_response() -> None:
    validate_candles_values(DzengiKlinesResponse(items=()))
