# pylint:disable=redefined-outer-name
# pylint:disable=too-many-arguments
from copy import copy
from datetime import timedelta

import pytest

from t_tech.invest.schemas import (
    CandleInterval,
    GetCandlesResponse,
    HistoricCandle,
    Quotation,
)
from t_tech.invest.services import MarketDataService, Services
from t_tech.invest.utils import now


@pytest.fixture()
def figi():
    return "figi"


@pytest.fixture()
def from_():
    return now() - timedelta(days=31)


@pytest.fixture()
def to():
    return now()


@pytest.fixture()
def historical_candle():
    quotation = Quotation(units=100, nano=0)
    return HistoricCandle(
        open=quotation,
        high=quotation,
        low=quotation,
        close=quotation,
        volume=100,
        time=now(),
        is_complete=False,
    )


@pytest.fixture()
def candles_response(historical_candle):
    return GetCandlesResponse(candles=[historical_candle])


@pytest.fixture()
def market_data_service(mocker):
    return mocker.Mock(spec=MarketDataService)


class TestGetAllCandles:
    @pytest.mark.parametrize(
        ("interval", "call_count"),
        [
            (CandleInterval.CANDLE_INTERVAL_5_SEC, 224),
            (CandleInterval.CANDLE_INTERVAL_10_SEC, 224),
            (CandleInterval.CANDLE_INTERVAL_30_SEC, 38),
            (CandleInterval.CANDLE_INTERVAL_1_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_2_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_3_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_5_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_10_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_15_MIN, 31),
            (CandleInterval.CANDLE_INTERVAL_HOUR, 5),
            (CandleInterval.CANDLE_INTERVAL_2_HOUR, 5),
            (CandleInterval.CANDLE_INTERVAL_4_HOUR, 5),
            (CandleInterval.CANDLE_INTERVAL_DAY, 1),
            (CandleInterval.CANDLE_INTERVAL_WEEK, 1),
            (CandleInterval.CANDLE_INTERVAL_MONTH, 1),
        ],
    )
    @pytest.mark.parametrize("use_to", [True, False])
    @pytest.mark.freeze_time("2023-10-21")
    def test_get_all_candles(
        self,
        figi,
        mocker,
        market_data_service,
        from_,
        to,
        candles_response,
        interval,
        call_count,
        use_to,
    ):
        services = mocker.Mock()
        services.market_data = market_data_service
        market_data_service.get_candles.return_value = candles_response

        to_kwarg = {}
        if use_to:
            to_kwarg = {"to": to}
        result = list(
            Services.get_all_candles(
                services,
                figi=figi,
                interval=interval,
                from_=from_,
                **to_kwarg,
            )
        )

        assert result == candles_response.candles
        assert market_data_service.get_candles.call_count == call_count

    @pytest.mark.parametrize(
        "interval",
        [
            *[
                interval
                for interval in CandleInterval
                if interval != CandleInterval.CANDLE_INTERVAL_UNSPECIFIED
            ],
        ],
    )
    def test_deduplicates(
        self,
        figi,
        mocker,
        market_data_service,
        from_,
        to,
        candles_response,
        interval,
        historical_candle,
    ):
        services = mocker.Mock()
        services.market_data = market_data_service

        def _get_duplicated_candle_response(*args, **kwargs):
            return GetCandlesResponse(
                candles=[copy(historical_candle) for _ in range(3)]
            )

        market_data_service.get_candles = _get_duplicated_candle_response

        candles = list(
            Services.get_all_candles(
                services,
                figi=figi,
                interval=interval,
                from_=from_,
                to=to,
            )
        )

        assert len(candles) == 1
