"""
Position rating service with Redis caching.

Provides cached access to position ratings with automatic
expiration and fallback to API.

Author: Claude
Date: 2025-11-03
Phase: 3E-Final
"""

import json
import logging

from redis.exceptions import RedisError

from app.models.player_models import PositionRating
from app.services.pd_api_client import pd_api_client

logger = logging.getLogger(f"{__name__}.PositionRatingService")

# Redis key pattern: "position_ratings:{card_id}"
# TTL: 86400 seconds (24 hours)
REDIS_KEY_PREFIX = "position_ratings"
REDIS_TTL_SECONDS = 86400  # 24 hours


class PositionRatingService:
    """Service for position rating lookup with caching."""

    def __init__(self, use_cache: bool = True):
        """
        Initialize position rating service.

        Args:
            use_cache: Whether to use caching (default True)
        """
        self.use_cache = use_cache

    def _get_redis_key(self, card_id: int) -> str:
        """
        Get Redis key for card ratings.

        Args:
            card_id: PD card ID

        Returns:
            Redis key string
        """
        return f"{REDIS_KEY_PREFIX}:{card_id}"

    async def get_ratings_for_card(
        self, card_id: int, league_id: str
    ) -> list[PositionRating]:
        """
        Get all position ratings for a card with Redis caching.

        Args:
            card_id: PD card ID
            league_id: League identifier ('pd')

        Returns:
            List of PositionRating objects
        """
        # Only cache for PD league
        if league_id != "pd":
            logger.debug(f"Skipping cache for non-PD league: {league_id}")
            return []

        # Try Redis cache first
        if self.use_cache:
            try:
                from app.services import redis_client

                if redis_client.is_connected:
                    redis_key = self._get_redis_key(card_id)
                    cached_json = await redis_client.client.get(redis_key)

                    if cached_json:
                        logger.debug(f"Redis cache hit for card {card_id}")
                        cached_data = json.loads(cached_json)
                        return [PositionRating(**data) for data in cached_data]
                    logger.debug(f"Redis cache miss for card {card_id}")
                else:
                    logger.warning("Redis not connected, skipping cache")

            except RedisError as e:
                logger.warning(
                    f"Redis error for card {card_id}: {e}, falling back to API"
                )
            except Exception as e:
                logger.error(f"Unexpected cache error for card {card_id}: {e}")

        # Cache miss or error - fetch from API
        logger.debug(f"Fetching ratings from API for card {card_id}")
        try:
            # Note: card_id maps to player_id in PD API terminology
            ratings = await pd_api_client.get_position_ratings(player_id=card_id)

            # Cache the results in Redis with TTL
            if self.use_cache and ratings:
                try:
                    from app.services import redis_client

                    if redis_client.is_connected:
                        redis_key = self._get_redis_key(card_id)
                        ratings_json = json.dumps([r.model_dump() for r in ratings])
                        await redis_client.client.setex(
                            redis_key, REDIS_TTL_SECONDS, ratings_json
                        )
                        logger.debug(
                            f"Cached {len(ratings)} ratings for card {card_id} (TTL: {REDIS_TTL_SECONDS}s)"
                        )
                except RedisError as e:
                    logger.warning(f"Failed to cache ratings for card {card_id}: {e}")

            return ratings

        except Exception as e:
            logger.error(f"Failed to fetch ratings for card {card_id}: {e}")
            return []  # Return empty list on error

    async def get_rating_for_position(
        self, card_id: int, position: str, league_id: str
    ) -> PositionRating | None:
        """
        Get rating for specific position.

        Args:
            card_id: PD card ID
            position: Position code (SS, LF, etc.)
            league_id: League identifier

        Returns:
            PositionRating if found, None otherwise
        """
        ratings = await self.get_ratings_for_card(card_id, league_id)

        for rating in ratings:
            if rating.position == position:
                return rating

        logger.warning(f"No rating found for card {card_id} at position {position}")
        return None

    async def clear_cache(self, card_id: int | None = None) -> None:
        """
        Clear Redis cache for position ratings.

        Args:
            card_id: If provided, clear only this card's cache.
                     If None, clear all position rating caches.
        """
        try:
            from app.services import redis_client

            if not redis_client.is_connected:
                logger.warning("Redis not connected, cannot clear cache")
                return

            if card_id is not None:
                # Clear specific card
                redis_key = self._get_redis_key(card_id)
                await redis_client.client.delete(redis_key)
                logger.info(f"Cleared cache for card {card_id}")
            else:
                # Clear all position rating caches
                pattern = f"{REDIS_KEY_PREFIX}:*"
                keys = []
                async for key in redis_client.client.scan_iter(match=pattern):
                    keys.append(key)

                if keys:
                    await redis_client.client.delete(*keys)
                    logger.info(f"Cleared {len(keys)} position rating cache entries")
                else:
                    logger.info("No position rating cache entries to clear")

        except RedisError as e:
            logger.error(f"Failed to clear cache: {e}")
        except Exception as e:
            logger.error(f"Unexpected error clearing cache: {e}")


# Singleton instance
position_rating_service = PositionRatingService()
