"""
VYNDR Data Warehouse
Local-first data layer with game-day TTL override.
Every external API response stored locally. Check cache first, API only if stale.
"""

import logging
import time as _time
from datetime import datetime, timedelta

from utils.retry import api_call_with_retry

logger = logging.getLogger('vyndr')

# In-memory cache (process-local). Supabase backing store for persistence across restarts.
_local_cache = {}

DATA_FRESHNESS = {
    'odds': {'default_ttl': 0.25, 'game_day_ttl': 0.083},           # 15min / 5min
    'lineups': {'default_ttl': 1.0, 'game_day_ttl': 0.25},          # 1hr / 15min
    'player_stats': {'default_ttl': 24, 'game_day_ttl': 6},         # 24hr / 6hr
    'weather': {'default_ttl': 6, 'game_day_ttl': 0.5},             # 6hr / 30min (continuous)
    'park_factors': {'default_ttl': 720, 'game_day_ttl': 720},      # 30 days
    'reporter_feed': {'default_ttl': 0.017, 'game_day_ttl': 0.017}  # ~1min
}


def get_from_local_cache(cache_key):
    """
    Retrieve data from in-memory cache.

    Args:
        cache_key: Unique cache key string.

    Returns:
        Dict with 'data' and 'fetched_at' keys, or None if not cached.
    """
    return _local_cache.get(cache_key)


def store_in_local_cache(cache_key, data):
    """
    Store data in in-memory cache with timestamp.

    Args:
        cache_key: Unique cache key string.
        data: Any serializable data to cache.
    """
    _local_cache[cache_key] = {
        'data': data,
        'fetched_at': datetime.utcnow().isoformat()
    }


def is_fresh(fetched_at_str, ttl_hours):
    """
    Check if cached data is still within its TTL.

    Args:
        fetched_at_str: ISO format timestamp of when data was fetched.
        ttl_hours: Time-to-live in hours.

    Returns:
        True if data is still fresh, False if stale.
    """
    try:
        fetched_at = datetime.fromisoformat(fetched_at_str)
        age_hours = (datetime.utcnow() - fetched_at).total_seconds() / 3600
        return age_hours < ttl_hours
    except (ValueError, TypeError):
        return False


def clear_cache(cache_key=None):
    """
    Clear local cache. If cache_key provided, clear only that key.
    Otherwise clear entire cache.
    """
    if cache_key:
        _local_cache.pop(cache_key, None)
    else:
        _local_cache.clear()


def fetch_with_cache(cache_key, fetch_func, data_type='player_stats',
                     has_game_today=False, *args, **kwargs):
    """
    Fetch data with cache-first strategy and game-day TTL override.

    Args:
        cache_key: Unique identifier for this data.
        fetch_func: Callable that fetches fresh data from external source.
        data_type: Key into DATA_FRESHNESS for TTL configuration.
        has_game_today: If True, use shorter game-day TTL.
        *args, **kwargs: Passed to fetch_func.

    Returns:
        Fetched data dict, or None if both cache and API fail.
        Stale data includes '_stale': True flag.
    """
    freshness = DATA_FRESHNESS.get(data_type, {'default_ttl': 6, 'game_day_ttl': 6})
    ttl = freshness['game_day_ttl'] if has_game_today else freshness['default_ttl']

    # Check local cache first
    local = get_from_local_cache(cache_key)
    if local and is_fresh(local['fetched_at'], ttl):
        return local['data']

    # Fetch fresh data through retry wrapper
    fresh_data = api_call_with_retry(fetch_func, *args, **kwargs)
    if fresh_data is not None:
        store_in_local_cache(cache_key, fresh_data)
        return fresh_data

    # Fallback to stale cache if API failed
    if local:
        logger.warning(f'[VYNDR] Using stale cache for {cache_key}')
        stale_data = local['data']
        if isinstance(stale_data, dict):
            return {**stale_data, '_stale': True}
        return stale_data

    return None
