"""
Forecast event consumer for the forecasting service
Handles events that should trigger cache invalidation for aggregated forecasts
"""

import logging
from typing import Dict, Any, Optional
import json
import redis.asyncio as redis

logger = logging.getLogger(__name__)


class ForecastEventConsumer:
    """
    Consumer for forecast events that may trigger cache invalidation
    """
    
    def __init__(self, redis_client: redis.Redis):
        self.redis_client = redis_client

    async def handle_forecast_updated(self, event_data: Dict[str, Any]):
        """
        Handle forecast updated event
        Invalidate parent tenant's aggregated forecast cache if this tenant is a child
        """
        try:
            logger.info(f"Handling forecast updated event: {event_data}")
            
            tenant_id = event_data.get('tenant_id')
            forecast_date = event_data.get('forecast_date')
            product_id = event_data.get('product_id')
            updated_at = event_data.get('updated_at', None)
            
            if not tenant_id:
                logger.error("Missing tenant_id in forecast event")
                return
            
            # Check if this tenant is a child tenant (has parent)
            # In a real implementation, this would call the tenant service to check hierarchy
            parent_tenant_id = await self._get_parent_tenant_id(tenant_id)
            
            if parent_tenant_id:
                # Invalidate parent's aggregated forecast cache
                await self._invalidate_parent_aggregated_cache(
                    parent_tenant_id=parent_tenant_id,
                    child_tenant_id=tenant_id,
                    forecast_date=forecast_date,
                    product_id=product_id
                )
            
            logger.info(f"Forecast updated event processed for tenant {tenant_id}")
            
        except Exception as e:
            logger.error(f"Error handling forecast updated event: {e}", exc_info=True)
            raise

    async def handle_forecast_created(self, event_data: Dict[str, Any]):
        """
        Handle forecast created event
        Similar to update, may affect parent tenant's aggregated forecasts
        """
        await self.handle_forecast_updated(event_data)

    async def handle_forecast_deleted(self, event_data: Dict[str, Any]):
        """
        Handle forecast deleted event
        Similar to update, may affect parent tenant's aggregated forecasts
        """
        try:
            logger.info(f"Handling forecast deleted event: {event_data}")
            
            tenant_id = event_data.get('tenant_id')
            forecast_date = event_data.get('forecast_date')
            product_id = event_data.get('product_id')
            
            if not tenant_id:
                logger.error("Missing tenant_id in forecast delete event")
                return
            
            # Check if this tenant is a child tenant
            parent_tenant_id = await self._get_parent_tenant_id(tenant_id)
            
            if parent_tenant_id:
                # Invalidate parent's aggregated forecast cache
                await self._invalidate_parent_aggregated_cache(
                    parent_tenant_id=parent_tenant_id,
                    child_tenant_id=tenant_id,
                    forecast_date=forecast_date,
                    product_id=product_id
                )
            
            logger.info(f"Forecast deleted event processed for tenant {tenant_id}")
            
        except Exception as e:
            logger.error(f"Error handling forecast deleted event: {e}", exc_info=True)
            raise

    async def _get_parent_tenant_id(self, tenant_id: str) -> Optional[str]:
        """
        Get parent tenant ID for a child tenant using the tenant service
        """
        try:
            from shared.clients.tenant_client import TenantServiceClient
            from shared.config.base import get_settings

            # Create tenant client
            config = get_settings()
            tenant_client = TenantServiceClient(config)

            # Get parent tenant information
            parent_tenant = await tenant_client.get_parent_tenant(tenant_id)

            if parent_tenant:
                parent_tenant_id = parent_tenant.get('id')
                logger.info(f"Found parent tenant {parent_tenant_id} for child tenant {tenant_id}")
                return parent_tenant_id
            else:
                logger.debug(f"No parent tenant found for tenant {tenant_id} (tenant may be standalone or parent)")
                return None

        except Exception as e:
            logger.error(f"Error getting parent tenant ID for {tenant_id}: {e}")
            return None

    async def _invalidate_parent_aggregated_cache(
        self,
        parent_tenant_id: str,
        child_tenant_id: str,
        forecast_date: Optional[str] = None,
        product_id: Optional[str] = None
    ):
        """
        Invalidate parent tenant's aggregated forecast cache
        """
        try:
            # Pattern to match all aggregated forecast cache keys for this parent
            # Format: agg_forecast:{parent_tenant_id}:{start_date}:{end_date}:{product_id}
            pattern = f"agg_forecast:{parent_tenant_id}:*:*:*"
            
            # Find all matching keys and delete them
            keys_to_delete = []
            async for key in self.redis_client.scan_iter(match=pattern):
                if isinstance(key, bytes):
                    key = key.decode('utf-8')
                keys_to_delete.append(key)
            
            if keys_to_delete:
                await self.redis_client.delete(*keys_to_delete)
                logger.info(f"Invalidated {len(keys_to_delete)} aggregated forecast cache entries for parent tenant {parent_tenant_id}")
            else:
                logger.info(f"No aggregated forecast cache entries found to invalidate for parent tenant {parent_tenant_id}")
                
        except Exception as e:
            logger.error(f"Error invalidating parent aggregated cache: {e}", exc_info=True)
            raise

    async def handle_tenant_hierarchy_changed(self, event_data: Dict[str, Any]):
        """
        Handle tenant hierarchy change event
        This could be when a tenant becomes a child of another, or when the hierarchy changes
        """
        try:
            logger.info(f"Handling tenant hierarchy change event: {event_data}")
            
            tenant_id = event_data.get('tenant_id')
            parent_tenant_id = event_data.get('parent_tenant_id')
            action = event_data.get('action')  # 'added', 'removed', 'changed'
            
            # Invalidate any cached aggregated forecasts that might be affected
            if parent_tenant_id:
                # If this child tenant changed, invalidate parent's cache
                await self._invalidate_parent_aggregated_cache(
                    parent_tenant_id=parent_tenant_id,
                    child_tenant_id=tenant_id
                )
            
            # If this was a former parent tenant that's no longer a parent, 
            # its aggregated cache might need to be invalidated differently
            if action == 'removed' and event_data.get('was_parent'):
                # Invalidate its own aggregated cache since it's no longer a parent
                # This would be handled by tenant service events
                pass
                
        except Exception as e:
            logger.error(f"Error handling tenant hierarchy change event: {e}", exc_info=True)
            raise