"""
Event Scheduler for automatic event launching in marathons.
"""
import asyncio
import random
from datetime import datetime, timedelta
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models import Marathon, MarathonStatus, Event, EventType
from app.services.events import EventService


# Configuration
CHECK_INTERVAL_SECONDS = 300  # Check every 5 minutes
EVENT_PROBABILITY = 0.1  # 10% chance per check to start an event
MIN_EVENT_GAP_HOURS = 4  # Minimum hours between events

# Events that can be auto-triggered (excluding common_enemy which needs a challenge_id)
AUTO_EVENT_TYPES = [
    EventType.GOLDEN_HOUR,
    EventType.DOUBLE_RISK,
    EventType.JACKPOT,
    EventType.GAME_CHOICE,
]


class EventScheduler:
    """Background scheduler for automatic event management."""

    def __init__(self):
        self._running = False
        self._task: asyncio.Task | None = None

    async def start(self, session_factory) -> None:
        """Start the scheduler background task."""
        if self._running:
            return

        self._running = True
        self._task = asyncio.create_task(self._run_loop(session_factory))
        print("[EventScheduler] Started")

    async def stop(self) -> None:
        """Stop the scheduler."""
        self._running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
        print("[EventScheduler] Stopped")

    async def _run_loop(self, session_factory) -> None:
        """Main scheduler loop."""
        while self._running:
            try:
                async with session_factory() as db:
                    await self._process_events(db)
            except Exception as e:
                print(f"[EventScheduler] Error in loop: {e}")

            await asyncio.sleep(CHECK_INTERVAL_SECONDS)

    async def _process_events(self, db: AsyncSession) -> None:
        """Process events - cleanup expired and potentially start new ones."""
        # 1. Cleanup expired events
        await self._cleanup_expired_events(db)

        # 2. Maybe start new events for eligible marathons
        await self._maybe_start_events(db)

    async def _cleanup_expired_events(self, db: AsyncSession) -> None:
        """End any events that have expired."""
        now = datetime.utcnow()

        result = await db.execute(
            select(Event).where(
                Event.is_active == True,
                Event.end_time < now,
            )
        )
        expired_events = result.scalars().all()

        for event in expired_events:
            event.is_active = False
            print(f"[EventScheduler] Ended expired event {event.id} ({event.type})")

        if expired_events:
            await db.commit()

    async def _maybe_start_events(self, db: AsyncSession) -> None:
        """Potentially start new events for eligible marathons."""
        # Get active marathons with auto_events enabled
        result = await db.execute(
            select(Marathon).where(
                Marathon.status == MarathonStatus.ACTIVE.value,
                Marathon.auto_events_enabled == True,
            )
        )
        marathons = result.scalars().all()

        event_service = EventService()

        for marathon in marathons:
            # Skip if random chance doesn't hit
            if random.random() > EVENT_PROBABILITY:
                continue

            # Check if there's already an active event
            active_event = await event_service.get_active_event(db, marathon.id)
            if active_event:
                continue

            # Check if enough time has passed since last event
            result = await db.execute(
                select(Event)
                .where(Event.marathon_id == marathon.id)
                .order_by(Event.end_time.desc())
                .limit(1)
            )
            last_event = result.scalar_one_or_none()

            if last_event:
                time_since_last = datetime.utcnow() - last_event.end_time
                if time_since_last < timedelta(hours=MIN_EVENT_GAP_HOURS):
                    continue

            # Start a random event
            event_type = random.choice(AUTO_EVENT_TYPES)

            try:
                event = await event_service.start_event(
                    db=db,
                    marathon_id=marathon.id,
                    event_type=event_type.value,
                    created_by_id=None,  # null = auto-started
                )
                print(
                    f"[EventScheduler] Auto-started {event_type.value} for marathon {marathon.id}"
                )
            except Exception as e:
                print(
                    f"[EventScheduler] Failed to start event for marathon {marathon.id}: {e}"
                )


# Global scheduler instance
event_scheduler = EventScheduler()
