import sys
import os
import pytest
from unittest.mock import patch, MagicMock
from httpx import AsyncClient, ASGITransport
import pandas as pd

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from app.main import app

MOCK_CAREER_DF = pd.DataFrame([{
    "SEASON_ID": "2025-26",
    "TEAM_ABBREVIATION": "DEN",
    "PTS": 26.3, "REB": 12.4, "AST": 9.1, "FG3M": 1.1,
    "BLK": 0.7, "STL": 1.4, "TOV": 3.2, "MIN": 34.2, "GP": 65,
}])

MOCK_GAMELOG_DF = pd.DataFrame([
    {
        "GAME_DATE": "MAR 21, 2026", "MATCHUP": "DEN vs. LAL",
        "TEAM_ABBREVIATION": "DEN",
        "PTS": 30, "REB": 15, "AST": 10, "FG3M": 2, "BLK": 1, "STL": 2, "TOV": 3, "MIN": 36,
    },
    {
        "GAME_DATE": "MAR 20, 2026", "MATCHUP": "DEN @ PHX",
        "TEAM_ABBREVIATION": "DEN",
        "PTS": 22, "REB": 10, "AST": 8, "FG3M": 0, "BLK": 0, "STL": 1, "TOV": 4, "MIN": 32,
    },
])

MOCK_PLAYERS = [{"id": 203999, "full_name": "Nikola Jokic", "is_active": True}]


def mock_career(*args, **kwargs):
    m = MagicMock()
    m.get_data_frames.return_value = [MOCK_CAREER_DF]
    return m


def mock_gamelog(*args, **kwargs):
    m = MagicMock()
    m.get_data_frames.return_value = [MOCK_GAMELOG_DF]
    return m


@pytest.fixture
def mock_nba_api():
    with patch("app.services.stats.playercareerstats.PlayerCareerStats", side_effect=mock_career), \
         patch("app.services.stats.playergamelog.PlayerGameLog", side_effect=mock_gamelog), \
         patch("app.utils.player_map.players.get_players", return_value=MOCK_PLAYERS), \
         patch("app.services.stats.cache_get", return_value=None), \
         patch("app.services.stats.cache_set"), \
         patch("app.utils.player_map.cache_get", return_value=None), \
         patch("app.utils.player_map.cache_set"), \
         patch("app.services.stats.time.sleep"):
        yield


@pytest.mark.asyncio
async def test_health():
    with patch("app.main.cache_health", return_value=True):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            resp = await client.get("/health")
            assert resp.status_code == 200
            assert resp.json()["status"] == "ok"


@pytest.mark.asyncio
async def test_player_search(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/players/search?name=Jokic")
        assert resp.status_code == 200
        assert len(resp.json()["results"]) > 0
        assert resp.json()["results"][0]["full_name"] == "Nikola Jokic"


@pytest.mark.asyncio
async def test_player_search_not_found():
    with patch("app.utils.player_map.players.get_players", return_value=[]), \
         patch("app.utils.player_map.cache_get", return_value=None), \
         patch("app.utils.player_map.cache_set"):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            resp = await client.get("/players/search?name=Zzzzzzz")
            assert resp.status_code == 404


@pytest.mark.asyncio
async def test_season_avg(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/season-avg?player=Nikola Jokic&season=2025-26")
        assert resp.status_code == 200
        data = resp.json()
        assert data["player"] == "Nikola Jokic"
        assert data["team"] == "DEN"
        assert "points" in data["stats"]
        assert "pra" in data["stats"]


@pytest.mark.asyncio
async def test_season_avg_invalid_stat_type(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/season-avg?player=Jokic&stat_type=invalid")
        assert resp.status_code == 400


@pytest.mark.asyncio
async def test_last_n(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/last-n?player=Nikola Jokic&n=2")
        assert resp.status_code == 200
        data = resp.json()
        assert data["last_n"] == 2
        assert "points" in data["stats"]


@pytest.mark.asyncio
async def test_last_n_clamps_max(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/last-n?player=Nikola Jokic&n=50")
        # FastAPI validates n <= 30, returns 422
        assert resp.status_code == 422


@pytest.mark.asyncio
async def test_splits_home_away(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/splits?player=Nikola Jokic&stat_type=points&split_type=home_away")
        assert resp.status_code == 200
        data = resp.json()
        assert "home" in data["splits"]
        assert "away" in data["splits"]


@pytest.mark.asyncio
async def test_splits_vs_team_requires_opponent(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/splits?player=Jokic&stat_type=points&split_type=vs_team")
        assert resp.status_code == 400
        assert "opponent" in resp.json()["detail"]


@pytest.mark.asyncio
async def test_splits_invalid_split_type(mock_nba_api):
    transport = ASGITransport(app=app)
    async with AsyncClient(transport=transport, base_url="http://test") as client:
        resp = await client.get("/stats/splits?player=Jokic&stat_type=points&split_type=invalid")
        assert resp.status_code == 400


@pytest.mark.asyncio
async def test_season_avg_player_not_found():
    with patch("app.utils.player_map.players.get_players", return_value=[]), \
         patch("app.utils.player_map.cache_get", return_value=None), \
         patch("app.utils.player_map.cache_set"), \
         patch("app.services.stats.cache_get", return_value=None), \
         patch("app.services.stats.time.sleep"):
        transport = ASGITransport(app=app)
        async with AsyncClient(transport=transport, base_url="http://test") as client:
            resp = await client.get("/stats/season-avg?player=Nobody")
            assert resp.status_code == 404
