"""
Integration tests for Position Rating API and caching.

These tests make REAL API calls to the PD API to verify the integration works.
Run manually with real API to validate before deploying.

Author: Claude
Date: 2025-11-03
"""
import pytest
import logging
from app.services.pd_api_client import pd_api_client
from app.services.position_rating_service import position_rating_service
from app.models.player_models import PositionRating

logger = logging.getLogger(__name__)


@pytest.mark.integration
class TestPdApiClientRealApi:
    """Test PD API client with real API calls."""

    async def test_fetch_position_ratings_real_api(self):
        """
        Test fetching position ratings from real PD API.

        Uses a known PD card ID to verify API integration.
        This test makes a REAL API call to https://pd.manticorum.com
        """
        # Use a known PD card ID (example: a common player card)
        # TODO: Replace with actual card ID from PD league
        test_card_id = 1000  # Replace with real card ID

        try:
            # Fetch ratings from API
            ratings = await pd_api_client.get_position_ratings(test_card_id)

            # Verify response structure
            assert isinstance(ratings, list), "Should return list of PositionRating objects"

            if len(ratings) > 0:
                # Verify first rating structure
                first_rating = ratings[0]
                assert isinstance(first_rating, PositionRating)
                assert hasattr(first_rating, 'position')
                assert hasattr(first_rating, 'range')
                assert hasattr(first_rating, 'error')
                assert hasattr(first_rating, 'arm')

                # Verify field values are reasonable
                assert first_rating.position in ['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']
                assert 1 <= first_rating.range <= 5, "Range should be 1-5"
                assert 0 <= first_rating.error <= 88, "Error should be 0-88"

                logger.info(f"✓ Successfully fetched {len(ratings)} position ratings for card {test_card_id}")
                logger.info(f"  First rating: {first_rating.position} - range={first_rating.range}, error={first_rating.error}")

                # Print all ratings for verification
                for rating in ratings:
                    logger.info(
                        f"  {rating.position}: range={rating.range}, error={rating.error}, "
                        f"arm={rating.arm}, innings={rating.innings}"
                    )
            else:
                logger.warning(f"⚠ Card {test_card_id} has no position ratings (may be pitcher-only or invalid card)")

        except Exception as e:
            logger.error(f"✗ Failed to fetch ratings: {e}")
            pytest.fail(f"API call failed: {e}")


@pytest.mark.integration
class TestPositionRatingServiceRealApi:
    """Test position rating service with real API and caching."""

    async def test_caching_with_real_api(self):
        """
        Test that caching works with real API calls.

        Makes two requests for same card - second should hit cache.
        """
        test_card_id = 1000  # Replace with real card ID

        # Clear cache before test
        position_rating_service.clear_cache()

        # First request - should hit API
        logger.info(f"First request for card {test_card_id} (should hit API)...")
        ratings1 = await position_rating_service.get_ratings_for_card(
            card_id=test_card_id,
            league_id='pd'
        )

        # Second request - should hit cache
        logger.info(f"Second request for card {test_card_id} (should hit cache)...")
        ratings2 = await position_rating_service.get_ratings_for_card(
            card_id=test_card_id,
            league_id='pd'
        )

        # Both should return same data
        assert len(ratings1) == len(ratings2), "Cache should return same number of ratings"

        if len(ratings1) > 0:
            # Verify first rating is identical
            assert ratings1[0].position == ratings2[0].position
            assert ratings1[0].range == ratings2[0].range
            assert ratings1[0].error == ratings2[0].error

            logger.info(f"✓ Cache working: {len(ratings1)} ratings cached successfully")

    async def test_get_specific_position_real_api(self):
        """
        Test getting rating for specific position.

        Fetches all ratings then filters for specific position.
        """
        test_card_id = 1000  # Replace with real card ID
        test_position = 'SS'  # Look for shortstop rating

        # Clear cache before test
        position_rating_service.clear_cache()

        # Get rating for specific position
        logger.info(f"Fetching {test_position} rating for card {test_card_id}...")
        rating = await position_rating_service.get_rating_for_position(
            card_id=test_card_id,
            position=test_position,
            league_id='pd'
        )

        if rating:
            assert rating.position == test_position
            logger.info(
                f"✓ Found {test_position} rating: range={rating.range}, error={rating.error}, "
                f"arm={rating.arm}"
            )
        else:
            logger.warning(f"⚠ Card {test_card_id} doesn't play {test_position}")

    async def test_sba_league_skips_api(self):
        """
        Test that SBA league doesn't make API calls.

        Should return empty list immediately without hitting API.
        """
        test_card_id = 1000

        # SBA league should not call API
        logger.info(f"Requesting ratings for SBA league (should skip API)...")
        ratings = await position_rating_service.get_ratings_for_card(
            card_id=test_card_id,
            league_id='sba'
        )

        assert ratings == [], "SBA league should return empty list without API call"
        logger.info("✓ SBA league correctly skips API calls")


@pytest.mark.integration
class TestEndToEndPositionRatings:
    """Test complete end-to-end flow with real data."""

    async def test_full_integration_flow(self):
        """
        Complete integration test simulating game start with position ratings.

        Flow:
        1. Create game state
        2. Load position ratings for lineup
        3. Verify ratings attached to players
        4. Simulate X-Check defender lookup
        """
        from uuid import uuid4
        from app.models.game_models import GameState, LineupPlayerState, TeamLineupState
        from app.core.state_manager import state_manager

        # Create test game
        game_id = uuid4()
        state = GameState(
            game_id=game_id,
            league_id='pd',
            home_team_id=1,
            away_team_id=2
        )

        # Create test lineup with real PD card
        test_card_id = 1000  # Replace with real card ID
        lineup_player = LineupPlayerState(
            lineup_id=1,
            card_id=test_card_id,
            position='SS',
            batting_order=1,
            is_active=True
        )

        # Create team lineup
        team_lineup = TeamLineupState(
            team_id=1,
            players=[lineup_player]
        )

        # Cache lineup in state manager
        state_manager._states[game_id] = state
        state_manager.set_lineup(game_id, 1, team_lineup)

        logger.info(f"Created test game {game_id} with card {test_card_id} at SS")

        # Load position rating for the player
        logger.info("Loading position rating from API...")
        rating = await position_rating_service.get_rating_for_position(
            card_id=test_card_id,
            position='SS',
            league_id='pd'
        )

        if rating:
            # Attach rating to player
            lineup_player.position_rating = rating

            logger.info(
                f"✓ Loaded rating: SS range={rating.range}, error={rating.error}, "
                f"arm={rating.arm}"
            )

            # Test GameState defender lookup
            defender = state.get_defender_for_position('SS', state_manager)

            assert defender is not None, "Should find SS defender"
            assert defender.position_rating is not None, "Defender should have rating"
            assert defender.position_rating.range == rating.range
            assert defender.position_rating.error == rating.error

            logger.info(
                f"✓ GameState lookup successful: Found SS defender with "
                f"range={defender.position_rating.range}, error={defender.position_rating.error}"
            )

            # Cleanup
            state_manager.remove_game(game_id)
            position_rating_service.clear_cache()

        else:
            logger.warning(f"⚠ Card {test_card_id} doesn't have SS rating - test inconclusive")
            pytest.skip(f"Card {test_card_id} doesn't play SS - cannot test full flow")


if __name__ == '__main__':
    """
    Run these tests manually to verify API integration.

    Usage:
        source venv/bin/activate
        export PYTHONPATH=.
        python -m pytest tests/integration/test_position_ratings_api.py -v -s

    Or run specific test:
        python -m pytest tests/integration/test_position_ratings_api.py::TestPdApiClientRealApi::test_fetch_position_ratings_real_api -v -s
    """
    import asyncio

    # Example: Run test directly
    async def run_manual_test():
        """Manual test runner for quick verification."""
        print("\n" + "="*80)
        print("MANUAL API TEST - Fetching position ratings from PD API")
        print("="*80 + "\n")

        test_card_id = 1000  # Replace with known good card ID

        print(f"Fetching position ratings for card {test_card_id}...")
        try:
            ratings = await pd_api_client.get_position_ratings(test_card_id)

            print(f"\n✓ SUCCESS: Fetched {len(ratings)} position ratings\n")

            for rating in ratings:
                print(f"  {rating.position:3s}: range={rating.range}, error={rating.error:2d}, "
                      f"arm={rating.arm}, innings={rating.innings}")

            print(f"\nNow testing cache...")
            position_rating_service.clear_cache()

            # First call - API
            print("  First call (API)...")
            await position_rating_service.get_ratings_for_card(test_card_id, 'pd')

            # Second call - cache
            print("  Second call (cache)...")
            cached = await position_rating_service.get_ratings_for_card(test_card_id, 'pd')

            print(f"✓ Cache working: {len(cached)} ratings cached\n")

        except Exception as e:
            print(f"\n✗ FAILED: {e}\n")
            raise

    # Uncomment to run manual test:
    # asyncio.run(run_manual_test())
