"""
Event Repository
Data access layer for events
"""

from typing import List, Optional, Dict, Any
from datetime import date, datetime
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, and_, or_, func
from uuid import UUID
import structlog

from app.models.events import Event, EventTemplate
from shared.database.repository import BaseRepository

logger = structlog.get_logger()


class EventRepository(BaseRepository[Event]):
    """Repository for event management"""

    def __init__(self, session: AsyncSession):
        super().__init__(Event, session)

    async def get_events_by_date_range(
        self,
        tenant_id: UUID,
        start_date: date,
        end_date: date,
        event_types: List[str] = None,
        confirmed_only: bool = False
    ) -> List[Event]:
        """
        Get events within a date range.

        Args:
            tenant_id: Tenant UUID
            start_date: Start date (inclusive)
            end_date: End date (inclusive)
            event_types: Optional filter by event types
            confirmed_only: Only return confirmed events

        Returns:
            List of Event objects
        """
        try:
            query = select(Event).where(
                and_(
                    Event.tenant_id == tenant_id,
                    Event.event_date >= start_date,
                    Event.event_date <= end_date
                )
            )

            if event_types:
                query = query.where(Event.event_type.in_(event_types))

            if confirmed_only:
                query = query.where(Event.is_confirmed == True)

            query = query.order_by(Event.event_date)

            result = await self.session.execute(query)
            events = result.scalars().all()

            logger.debug("Retrieved events by date range",
                        tenant_id=str(tenant_id),
                        start_date=start_date.isoformat(),
                        end_date=end_date.isoformat(),
                        count=len(events))

            return list(events)

        except Exception as e:
            logger.error("Failed to get events by date range",
                        tenant_id=str(tenant_id),
                        error=str(e))
            return []

    async def get_events_for_date(
        self,
        tenant_id: UUID,
        event_date: date
    ) -> List[Event]:
        """
        Get all events for a specific date.

        Args:
            tenant_id: Tenant UUID
            event_date: Date to get events for

        Returns:
            List of Event objects
        """
        try:
            query = select(Event).where(
                and_(
                    Event.tenant_id == tenant_id,
                    Event.event_date == event_date
                )
            ).order_by(Event.start_time)

            result = await self.session.execute(query)
            events = result.scalars().all()

            return list(events)

        except Exception as e:
            logger.error("Failed to get events for date",
                        tenant_id=str(tenant_id),
                        error=str(e))
            return []

    async def get_upcoming_events(
        self,
        tenant_id: UUID,
        days_ahead: int = 30,
        limit: int = 100
    ) -> List[Event]:
        """
        Get upcoming events.

        Args:
            tenant_id: Tenant UUID
            days_ahead: Number of days to look ahead
            limit: Maximum number of events to return

        Returns:
            List of upcoming Event objects
        """
        try:
            from datetime import date, timedelta

            today = date.today()
            future_date = today + timedelta(days=days_ahead)

            query = select(Event).where(
                and_(
                    Event.tenant_id == tenant_id,
                    Event.event_date >= today,
                    Event.event_date <= future_date
                )
            ).order_by(Event.event_date).limit(limit)

            result = await self.session.execute(query)
            events = result.scalars().all()

            return list(events)

        except Exception as e:
            logger.error("Failed to get upcoming events",
                        tenant_id=str(tenant_id),
                        error=str(e))
            return []

    async def create_event(self, event_data: Dict[str, Any]) -> Event:
        """Create a new event"""
        try:
            event = Event(**event_data)
            self.session.add(event)
            await self.session.flush()

            logger.info("Created event",
                       event_id=str(event.id),
                       event_name=event.event_name,
                       event_date=event.event_date.isoformat())

            return event

        except Exception as e:
            logger.error("Failed to create event", error=str(e))
            raise

    async def update_event_actual_impact(
        self,
        event_id: UUID,
        actual_impact_multiplier: float,
        actual_sales_increase_percent: float
    ) -> Optional[Event]:
        """
        Update event with actual impact after it occurs.

        Args:
            event_id: Event UUID
            actual_impact_multiplier: Actual demand multiplier observed
            actual_sales_increase_percent: Actual sales increase percentage

        Returns:
            Updated Event or None
        """
        try:
            event = await self.get(event_id)
            if not event:
                return None

            event.actual_impact_multiplier = actual_impact_multiplier
            event.actual_sales_increase_percent = actual_sales_increase_percent

            await self.session.flush()

            logger.info("Updated event actual impact",
                       event_id=str(event_id),
                       actual_multiplier=actual_impact_multiplier)

            return event

        except Exception as e:
            logger.error("Failed to update event actual impact",
                        event_id=str(event_id),
                        error=str(e))
            return None

    async def get_events_by_type(
        self,
        tenant_id: UUID,
        event_type: str,
        limit: int = 100
    ) -> List[Event]:
        """Get events by type"""
        try:
            query = select(Event).where(
                and_(
                    Event.tenant_id == tenant_id,
                    Event.event_type == event_type
                )
            ).order_by(Event.event_date.desc()).limit(limit)

            result = await self.session.execute(query)
            events = result.scalars().all()

            return list(events)

        except Exception as e:
            logger.error("Failed to get events by type",
                        tenant_id=str(tenant_id),
                        event_type=event_type,
                        error=str(e))
            return []


class EventTemplateRepository(BaseRepository[EventTemplate]):
    """Repository for event template management"""

    def __init__(self, session: AsyncSession):
        super().__init__(EventTemplate, session)

    async def get_active_templates(self, tenant_id: UUID) -> List[EventTemplate]:
        """Get all active event templates for a tenant"""
        try:
            query = select(EventTemplate).where(
                and_(
                    EventTemplate.tenant_id == tenant_id,
                    EventTemplate.is_active == True
                )
            ).order_by(EventTemplate.template_name)

            result = await self.session.execute(query)
            templates = result.scalars().all()

            return list(templates)

        except Exception as e:
            logger.error("Failed to get active templates",
                        tenant_id=str(tenant_id),
                        error=str(e))
            return []

    async def create_template(self, template_data: Dict[str, Any]) -> EventTemplate:
        """Create a new event template"""
        try:
            template = EventTemplate(**template_data)
            self.session.add(template)
            await self.session.flush()

            logger.info("Created event template",
                       template_id=str(template.id),
                       template_name=template.template_name)

            return template

        except Exception as e:
            logger.error("Failed to create event template", error=str(e))
            raise
