"""
APScheduler integration for cron-style triggers.

Provides scheduling of periodic triggers (e.g., sync exchange state hourly,
recompute indicators every 5 minutes, daily portfolio reports).
"""

import logging
from typing import Optional

from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger as APSCronTrigger
from apscheduler.triggers.interval import IntervalTrigger

from .queue import TriggerQueue
from .types import Priority, Trigger

logger = logging.getLogger(__name__)


class TriggerScheduler:
    """
    Scheduler for periodic trigger execution.

    Wraps APScheduler to enqueue triggers at scheduled times.
    """

    def __init__(self, trigger_queue: TriggerQueue):
        """
        Initialize scheduler.

        Args:
            trigger_queue: TriggerQueue to enqueue triggers into
        """
        self.trigger_queue = trigger_queue
        self.scheduler = AsyncIOScheduler()
        self._job_counter = 0

    def start(self) -> None:
        """Start the scheduler"""
        self.scheduler.start()
        logger.info("TriggerScheduler started")

    def shutdown(self, wait: bool = True) -> None:
        """
        Shut down the scheduler.

        Args:
            wait: If True, wait for running jobs to complete
        """
        self.scheduler.shutdown(wait=wait)
        logger.info("TriggerScheduler shut down")

    def schedule_interval(
        self,
        trigger: Trigger,
        seconds: Optional[int] = None,
        minutes: Optional[int] = None,
        hours: Optional[int] = None,
        priority: Optional[Priority] = None,
    ) -> str:
        """
        Schedule a trigger to run at regular intervals.

        Args:
            trigger: Trigger to execute
            seconds: Interval in seconds
            minutes: Interval in minutes
            hours: Interval in hours
            priority: Priority override for execution

        Returns:
            Job ID (can be used to remove job later)

        Example:
            # Run every 5 minutes
            scheduler.schedule_interval(
                IndicatorUpdateTrigger("rsi_14"),
                minutes=5
            )
        """
        job_id = f"interval_{self._job_counter}"
        self._job_counter += 1

        async def job_func():
            await self.trigger_queue.enqueue(trigger, priority)

        self.scheduler.add_job(
            job_func,
            trigger=IntervalTrigger(seconds=seconds, minutes=minutes, hours=hours),
            id=job_id,
            name=f"Interval: {trigger.name}",
        )

        logger.info(
            f"Scheduled interval job: {job_id}, trigger={trigger.name}, "
            f"interval=(s={seconds}, m={minutes}, h={hours})"
        )

        return job_id

    def schedule_cron(
        self,
        trigger: Trigger,
        minute: Optional[str] = None,
        hour: Optional[str] = None,
        day: Optional[str] = None,
        month: Optional[str] = None,
        day_of_week: Optional[str] = None,
        priority: Optional[Priority] = None,
    ) -> str:
        """
        Schedule a trigger to run on a cron schedule.

        Args:
            trigger: Trigger to execute
            minute: Minute expression (0-59, *, */5, etc.)
            hour: Hour expression (0-23, *, etc.)
            day: Day of month expression (1-31, *, etc.)
            month: Month expression (1-12, *, etc.)
            day_of_week: Day of week expression (0-6, mon-sun, *, etc.)
            priority: Priority override for execution

        Returns:
            Job ID (can be used to remove job later)

        Example:
            # Run at 9:00 AM every weekday
            scheduler.schedule_cron(
                SyncExchangeStateTrigger(),
                hour="9",
                minute="0",
                day_of_week="mon-fri"
            )
        """
        job_id = f"cron_{self._job_counter}"
        self._job_counter += 1

        async def job_func():
            await self.trigger_queue.enqueue(trigger, priority)

        self.scheduler.add_job(
            job_func,
            trigger=APSCronTrigger(
                minute=minute,
                hour=hour,
                day=day,
                month=month,
                day_of_week=day_of_week,
            ),
            id=job_id,
            name=f"Cron: {trigger.name}",
        )

        logger.info(
            f"Scheduled cron job: {job_id}, trigger={trigger.name}, "
            f"schedule=(m={minute}, h={hour}, d={day}, dow={day_of_week})"
        )

        return job_id

    def remove_job(self, job_id: str) -> bool:
        """
        Remove a scheduled job.

        Args:
            job_id: Job ID returned from schedule_* methods

        Returns:
            True if job was removed, False if not found
        """
        try:
            self.scheduler.remove_job(job_id)
            logger.info(f"Removed scheduled job: {job_id}")
            return True
        except Exception as e:
            logger.warning(f"Could not remove job {job_id}: {e}")
            return False

    def get_jobs(self) -> list:
        """Get list of all scheduled jobs"""
        return self.scheduler.get_jobs()

    def __repr__(self) -> str:
        job_count = len(self.scheduler.get_jobs())
        running = self.scheduler.running
        return f"TriggerScheduler(running={running}, jobs={job_count})"
