"""Tests for dyfinance.download() wrapper.

Uses mocking to avoid network calls. Verifies:
- Cacheable intervals use per-ticker cache
- Intraday falls through to yfinance.download()
- All options produce correct output structure
"""

from unittest.mock import patch

import pandas as pd
import pytest

from helpers import FIXED_END, FIXED_START, make_raw_df


# ---------------------------------------------------------------------------
# Routing
# ---------------------------------------------------------------------------

class TestDownloadRouting:
    def test_cacheable_interval_uses_ticker_cache(self, mock_yf_ticker):
        """Daily interval should use per-ticker Ticker.history() cache path."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", multi_level_index=False,
        )

        assert isinstance(df, pd.DataFrame)
        assert not df.empty

    def test_intraday_falls_through(self):
        """Intraday intervals should fall through to yfinance.download()."""
        import dyfinance

        with patch("yfinance.download") as mock_dl:
            mock_dl.return_value = pd.DataFrame({"Close": [100.0]})

            dyfinance.download("AAPL", period="1d", interval="5m")

            mock_dl.assert_called_once()


# ---------------------------------------------------------------------------
# tickers parameter formats
# ---------------------------------------------------------------------------

class TestTickersFormat:
    def test_single_string(self, mock_yf_ticker):
        """Single ticker as string."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", multi_level_index=False,
        )

        assert isinstance(df, pd.DataFrame)
        assert not df.empty

    def test_space_separated_string(self, mock_yf_ticker):
        """Multiple tickers as space-separated string."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL MSFT", start=FIXED_START, end=FIXED_END, interval="1d",
        )

        assert isinstance(df, pd.DataFrame)
        assert not df.empty

    def test_list_format(self, mock_yf_ticker):
        """Multiple tickers as list."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            ["AAPL", "MSFT"], start=FIXED_START, end=FIXED_END, interval="1d",
        )

        assert isinstance(df, pd.DataFrame)
        assert not df.empty


# ---------------------------------------------------------------------------
# group_by parameter
# ---------------------------------------------------------------------------

class TestGroupByOption:
    def test_group_by_column(self, mock_yf_ticker):
        """group_by='column' should produce MultiIndex columns."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            ["AAPL", "MSFT"], start=FIXED_START, end=FIXED_END,
            interval="1d", group_by="column", multi_level_index=True,
        )

        assert isinstance(df.columns, pd.MultiIndex)

    def test_group_by_ticker(self, mock_yf_ticker):
        """group_by='ticker' should produce MultiIndex columns."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            ["AAPL", "MSFT"], start=FIXED_START, end=FIXED_END,
            interval="1d", group_by="ticker", multi_level_index=True,
        )

        assert isinstance(df.columns, pd.MultiIndex)


# ---------------------------------------------------------------------------
# multi_level_index parameter
# ---------------------------------------------------------------------------

class TestMultiLevelIndexOption:
    def test_multi_level_false_single_ticker(self, mock_yf_ticker):
        """multi_level_index=False with single ticker should produce flat columns."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", multi_level_index=False,
        )

        assert not isinstance(df.columns, pd.MultiIndex)
        assert "Close" in df.columns

    def test_multi_level_true_single_ticker(self, mock_yf_ticker):
        """multi_level_index=True with single ticker should produce MultiIndex."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", multi_level_index=True,
        )

        assert isinstance(df.columns, pd.MultiIndex)


# ---------------------------------------------------------------------------
# actions option in download
# ---------------------------------------------------------------------------

class TestDownloadActionsOption:
    @pytest.mark.parametrize("actions", [True, False])
    def test_actions_forwarded(self, mock_yf_ticker, actions):
        """actions parameter should be forwarded to Ticker.history()."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", actions=actions, multi_level_index=False,
        )

        if actions:
            assert "Dividends" in df.columns
        else:
            assert "Dividends" not in df.columns


# ---------------------------------------------------------------------------
# auto_adjust option in download
# ---------------------------------------------------------------------------

class TestDownloadAutoAdjustOption:
    @pytest.mark.parametrize("auto_adjust", [True, False])
    def test_auto_adjust_forwarded(self, mock_yf_ticker, auto_adjust):
        """auto_adjust parameter should be forwarded to Ticker.history()."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", auto_adjust=auto_adjust, multi_level_index=False,
        )

        if auto_adjust:
            assert "Adj Close" not in df.columns
        else:
            assert "Adj Close" in df.columns


# ---------------------------------------------------------------------------
# ignore_tz option
# ---------------------------------------------------------------------------

class TestIgnoreTzOption:
    def test_ignore_tz_true_strips_tz(self, mock_yf_ticker):
        """ignore_tz=True should strip timezone from index."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", ignore_tz=True, multi_level_index=False,
        )

        assert df.index.tz is None

    def test_ignore_tz_false_keeps_tz(self, mock_yf_ticker):
        """ignore_tz=False should keep timezone on index."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", ignore_tz=False, multi_level_index=False,
        )

        assert df.index.tz is not None


# ---------------------------------------------------------------------------
# Combined download options
# ---------------------------------------------------------------------------

class TestDownloadCombinedOptions:
    @pytest.mark.parametrize("auto_adjust", [True, False])
    @pytest.mark.parametrize("actions", [True, False])
    def test_download_option_combinations(self, mock_yf_ticker, auto_adjust, actions):
        """Various option combinations should produce valid DataFrames."""
        import dyfinance

        mock_yf_ticker.history.return_value = make_raw_df()

        df = dyfinance.download(
            "AAPL", start=FIXED_START, end=FIXED_END,
            interval="1d", auto_adjust=auto_adjust, actions=actions,
            multi_level_index=False,
        )

        assert isinstance(df, pd.DataFrame)
        assert not df.empty
        assert "Open" in df.columns
        assert "Close" in df.columns
