import pytest

from app.data_sources import build_provider
from app.data_sources.ghostfolio_api_provider import GhostfolioAPIDataProvider
from app.data_sources.mock_file_provider import MockFileDataProvider
from app.data_sources.mock_provider import MockPortfolioDataProvider
from app.ghostfolio_client import GhostfolioClient
from app.schemas import DATA_SOURCE_GHOSTFOLIO_API, DATA_SOURCE_MOCK, DATA_SOURCE_MOCK_FILE


def test_build_provider_returns_mock_for_mock_source():
    api_provider = GhostfolioAPIDataProvider(GhostfolioClient("https://ghostfol.io", token=None, timeout_seconds=10.0))
    provider = build_provider(DATA_SOURCE_MOCK, api_provider)
    assert isinstance(provider, MockPortfolioDataProvider)


def test_build_provider_returns_api_for_live_source():
    api_provider = GhostfolioAPIDataProvider(GhostfolioClient("https://ghostfol.io", token=None, timeout_seconds=10.0))
    provider = build_provider(DATA_SOURCE_GHOSTFOLIO_API, api_provider)
    assert provider is api_provider


def test_build_provider_returns_mock_file_for_mock_file_source():
    api_provider = GhostfolioAPIDataProvider(GhostfolioClient("https://ghostfol.io", token=None, timeout_seconds=10.0))
    provider = build_provider(DATA_SOURCE_MOCK_FILE, api_provider)
    assert isinstance(provider, MockFileDataProvider)


# ─── MockFileDataProvider unit tests ───────────────────────────────────────


@pytest.mark.asyncio
async def test_mock_file_portfolio_summary_has_many_holdings():
    provider = MockFileDataProvider()
    summary = await provider.get_portfolio_summary()
    assert summary["holdings_count"] >= 30
    assert summary["total_value"] > 100_000
    assert summary["currency"] == "USD"
    # Holdings should have required fields
    h = summary["holdings"][0]
    assert "symbol" in h
    assert "value" in h
    assert "allocation_pct" in h
    assert "sector" in h


@pytest.mark.asyncio
async def test_mock_file_portfolio_summary_filter_by_account():
    provider = MockFileDataProvider()
    # Fidelity account ID from the JSON
    fidelity_id = "65c71131-0604-42d2-8348-220169ed2a6f"
    full = await provider.get_portfolio_summary()
    filtered = await provider.get_portfolio_summary(account_id=fidelity_id)
    assert filtered["holdings_count"] < full["holdings_count"]
    assert filtered["total_value"] < full["total_value"]


@pytest.mark.asyncio
async def test_mock_file_transactions_returns_all():
    provider = MockFileDataProvider()
    txs = await provider.get_transactions()
    assert len(txs) > 500
    tx = txs[0]
    assert "date" in tx
    assert "type" in tx
    assert "symbol" in tx
    assert tx["type"] in ("BUY", "SELL", "DIVIDEND")


@pytest.mark.asyncio
async def test_mock_file_accounts():
    provider = MockFileDataProvider()
    accounts = await provider.get_accounts()
    assert len(accounts) == 5
    names = {a["name"] for a in accounts}
    assert "Charles Schwab" in names
    assert "Coinbase" in names
    assert "Fidelity" in names


@pytest.mark.asyncio
async def test_mock_file_performance():
    provider = MockFileDataProvider()
    perf = await provider.get_performance("max")
    assert "return_pct" in perf
    assert "absolute_gain" in perf
    assert perf["range"] == "max"
    # 1d should be much smaller than max
    perf_1d = await provider.get_performance("1d")
    assert abs(perf_1d["return_pct"]) < abs(perf["return_pct"])


@pytest.mark.asyncio
async def test_mock_file_market_data():
    provider = MockFileDataProvider()
    md = await provider.get_market_data(["NVDA", "TSLA", "NONEXISTENT"])
    assert "NVDA" in md
    assert "TSLA" in md
    assert "NONEXISTENT" not in md
    assert md["NVDA"]["price"] > 0
