"""
Tests for the Candles module.

Note: The candle data fetching has been moved to EDM (Exchange Data Manager).
These tests use mocked EDM responses to avoid requiring a running EDM server.
Functions like ts_of_n_minutes_ago and timeframe_to_minutes are tested in
test_shared_utilities.py.
"""
import datetime as dt
import pytest
import pandas as pd
from unittest.mock import MagicMock, patch

from candles import Candles
from Configuration import Configuration
from DataCache_v3 import DataCache


@pytest.fixture
def mock_edm_client():
    """Create a mock EDM client."""
    mock = MagicMock()
    # Mock get_candles_sync to return sample candle data
    sample_candles = pd.DataFrame({
        'time': [1700000000000, 1700000060000, 1700000120000, 1700000180000, 1700000240000],
        'open': [100.0, 101.0, 102.0, 101.5, 103.0],
        'high': [102.0, 103.0, 104.0, 103.5, 105.0],
        'low': [99.0, 100.0, 101.0, 100.5, 102.0],
        'close': [101.0, 102.0, 101.5, 103.0, 104.0],
        'volume': [1000.0, 1200.0, 800.0, 1500.0, 900.0]
    })
    mock.get_candles_sync.return_value = sample_candles
    return mock


@pytest.fixture
def mock_exchanges():
    """Create mock exchange interface."""
    return MagicMock()


@pytest.fixture
def mock_users():
    """Create mock users object."""
    mock = MagicMock()
    mock.get_chart_view.return_value = {'timeframe': '1m', 'exchange': 'binance', 'market': 'BTC/USDT'}
    return mock


@pytest.fixture
def data_cache():
    """Create a fresh DataCache."""
    return DataCache()


@pytest.fixture
def config():
    """Create a Configuration instance."""
    return Configuration()


@pytest.fixture
def candles(mock_exchanges, mock_users, data_cache, config, mock_edm_client):
    """Create a Candles instance with mocked dependencies."""
    return Candles(
        exchanges=mock_exchanges,
        users=mock_users,
        datacache=data_cache,
        config=config,
        edm_client=mock_edm_client
    )


class TestCandles:
    """Tests for the Candles class."""

    def test_candles_creation(self, candles):
        """Test that Candles object can be created."""
        assert candles is not None

    def test_get_last_n_candles(self, candles, mock_edm_client):
        """Test getting last N candles."""
        result = candles.get_last_n_candles(
            num_candles=5,
            asset='BTC/USDT',
            timeframe='1m',
            exchange='binance',
            user_name='test_user'
        )

        assert result is not None
        assert isinstance(result, pd.DataFrame)
        assert len(result) == 5
        assert 'open' in result.columns
        assert 'high' in result.columns
        assert 'low' in result.columns
        assert 'close' in result.columns
        assert 'volume' in result.columns

    def test_get_last_n_candles_caps_at_1000(self, candles, mock_edm_client):
        """Test that requests for more than 1000 candles are capped."""
        candles.get_last_n_candles(
            num_candles=2000,
            asset='BTC/USDT',
            timeframe='1m',
            exchange='binance',
            user_name='test_user'
        )

        # Check that EDM was called with capped limit
        call_args = mock_edm_client.get_candles_sync.call_args
        assert call_args.kwargs.get('limit', call_args[1].get('limit')) == 1000

    def test_candles_raises_without_edm(self, mock_exchanges, mock_users, data_cache, config):
        """Test that Candles raises error when EDM is not available."""
        candles_no_edm = Candles(
            exchanges=mock_exchanges,
            users=mock_users,
            datacache=data_cache,
            config=config,
            edm_client=None
        )

        with pytest.raises(RuntimeError, match="EDM client not initialized"):
            candles_no_edm.get_last_n_candles(
                num_candles=5,
                asset='BTC/USDT',
                timeframe='1m',
                exchange='binance',
                user_name='test_user'
            )

    def test_get_latest_values(self, candles, mock_edm_client):
        """Test getting latest values for a specific field."""
        result = candles.get_latest_values(
            value_name='close',
            symbol='BTC/USDT',
            timeframe='1m',
            exchange='binance',
            num_record=5,
            user_name='test_user'
        )

        assert result is not None
        # Should return series/list of close values
        assert len(result) <= 5

    def test_max_records_from_config(self, candles, config):
        """Test that max_records is loaded from config."""
        expected_max = config.get_setting('max_data_loaded')
        assert candles.max_records == expected_max

    def test_candle_cache_created(self, candles, data_cache):
        """Test that candle cache is created on initialization."""
        # The cache should exist
        assert 'candles' in data_cache.caches


class TestCandlesIntegration:
    """Integration-style tests that verify EDM client interaction."""

    def test_edm_client_called_correctly(self, candles, mock_edm_client):
        """Test that EDM client is called with correct parameters."""
        candles.get_last_n_candles(
            num_candles=10,
            asset='ETH/USDT',
            timeframe='5m',
            exchange='binance',
            user_name='test_user'
        )

        mock_edm_client.get_candles_sync.assert_called_once()
        call_kwargs = mock_edm_client.get_candles_sync.call_args.kwargs
        assert call_kwargs['symbol'] == 'ETH/USDT'
        assert call_kwargs['timeframe'] == '5m'
        assert call_kwargs['exchange'] == 'binance'
        assert call_kwargs['limit'] == 10
