"""
Enhanced Recurring Jobs System for ElephantQ.
Streamlined API with fluent interfaces and better integration.
"""

__all__ = [
    "every",
    "cron",
    "daily",
    "FluentRecurringScheduler",
    "Priority",
]

import asyncio
import json
import logging
import uuid
from datetime import datetime, timedelta, timezone
from enum import Enum
from typing import Any, Callable, Dict, List, Optional, Union

logger = logging.getLogger(__name__)

try:
    from croniter import croniter  # type: ignore[import-untyped]  # noqa: E402
except ImportError:
    croniter = None  # type: ignore[assignment,misc]


def _require_croniter():
    if croniter is None:
        raise ImportError(
            "croniter is required for recurring jobs. "
            "Install it with: pip install elephantq[scheduling]"
        )


from elephantq import enqueue  # noqa: E402
from elephantq.core.registry import get_job as get_registered_job  # noqa: E402
from elephantq.db.context import get_context_pool  # noqa: E402

from .flags import require_feature  # noqa: E402


class Priority(Enum):
    """Job priority levels"""

    URGENT = 1
    HIGH = 10
    NORMAL = 50
    LOW = 75
    BACKGROUND = 100


class FluentRecurringScheduler:
    """Enhanced fluent interface for recurring jobs"""

    def __init__(self, schedule_type: str, schedule_value: Union[str, int]):
        self.schedule_type = schedule_type  # 'cron' or 'interval'
        self.schedule_value = schedule_value
        self._priority: int = Priority.NORMAL.value
        self._queue: str = "default"
        self._max_attempts: int = 3
        self._job_kwargs: Dict[str, Any] = {}

    def priority(self, level: Union[Priority, int, str]) -> "FluentRecurringScheduler":
        """Set job priority"""
        if isinstance(level, Priority):
            self._priority = level.value
        elif isinstance(level, int):
            self._priority = level
        elif isinstance(level, str):
            priority_map = {
                "urgent": Priority.URGENT.value,
                "high": Priority.HIGH.value,
                "normal": Priority.NORMAL.value,
                "low": Priority.LOW.value,
                "background": Priority.BACKGROUND.value,
            }
            self._priority = priority_map.get(level.lower(), Priority.NORMAL.value)
        return self

    def queue(self, queue_name: str) -> "FluentRecurringScheduler":
        """Set target queue"""
        self._queue = queue_name
        return self

    def max_attempts(self, attempts: int) -> "FluentRecurringScheduler":
        """Set maximum retry attempts"""
        self._max_attempts = attempts
        return self

    def high_priority(self) -> "FluentRecurringScheduler":
        """Set high priority (convenience method)"""
        return self.priority(Priority.HIGH).queue("urgent")

    def background(self) -> "FluentRecurringScheduler":
        """Set background priority (convenience method)"""
        return self.priority(Priority.BACKGROUND).queue("background")

    def urgent(self) -> "FluentRecurringScheduler":
        """Set urgent priority (convenience method)"""
        return self.priority(Priority.URGENT).queue("urgent")

    async def schedule(self, job_func: Callable[..., Any], **job_kwargs) -> str:
        """Schedule the recurring job"""
        # Merge job kwargs
        final_kwargs = {**self._job_kwargs, **job_kwargs}

        # Add to recurring manager with all configuration
        job_id = await _enhanced_manager.add_recurring_job(
            job_func=job_func,
            schedule_type=self.schedule_type,
            schedule_value=self.schedule_value,
            priority=self._priority,
            queue=self._queue,
            max_attempts=self._max_attempts,
            job_kwargs=final_kwargs,
        )

        return job_id


class TimeIntervalBuilder:
    """Builder for time-based scheduling"""

    def __init__(self, amount: int):
        self.amount = amount

    def seconds(self) -> FluentRecurringScheduler:
        """Every N seconds"""
        return FluentRecurringScheduler("interval", self.amount)

    def minutes(self) -> FluentRecurringScheduler:
        """Every N minutes"""
        return FluentRecurringScheduler("interval", self.amount * 60)

    def hours(self) -> FluentRecurringScheduler:
        """Every N hours"""
        return FluentRecurringScheduler("interval", self.amount * 3600)

    def days(self) -> FluentRecurringScheduler:
        """Every N days"""
        return FluentRecurringScheduler("interval", self.amount * 86400)


class DailyScheduler(FluentRecurringScheduler):
    """Enhanced daily scheduler with time specification"""

    def __init__(self):
        super().__init__("cron", "0 0 * * *")  # Midnight by default

    def at(self, time: str) -> "DailyScheduler":
        """Set specific time (HH:MM format)"""
        try:
            hour, minute = map(int, time.split(":"))
            if not (0 <= hour <= 23 and 0 <= minute <= 59):
                raise ValueError("Invalid time format")
            self.schedule_value = f"{minute} {hour} * * *"
        except (ValueError, AttributeError):
            raise ValueError("Time must be in HH:MM format (24-hour)")
        return self


class WeeklyScheduler(FluentRecurringScheduler):
    """Enhanced weekly scheduler"""

    def __init__(self):
        super().__init__("cron", "0 0 * * 0")  # Sunday midnight by default
        self._day = 0  # Sunday
        self._hour = 0
        self._minute = 0

    def on(self, day: Union[str, int]) -> "WeeklyScheduler":
        """Set day of week"""
        if isinstance(day, str):
            day_map = {
                "sunday": 0,
                "sun": 0,
                "monday": 1,
                "mon": 1,
                "tuesday": 2,
                "tue": 2,
                "wednesday": 3,
                "wed": 3,
                "thursday": 4,
                "thu": 4,
                "friday": 5,
                "fri": 5,
                "saturday": 6,
                "sat": 6,
            }
            self._day = day_map.get(day.lower(), 0)
        else:
            self._day = day % 7

        self._update_cron()
        return self

    def at(self, time: str) -> "WeeklyScheduler":
        """Set specific time"""
        try:
            self._hour, self._minute = map(int, time.split(":"))
            if not (0 <= self._hour <= 23 and 0 <= self._minute <= 59):
                raise ValueError("Invalid time format")
        except (ValueError, AttributeError):
            raise ValueError("Time must be in HH:MM format")

        self._update_cron()
        return self

    def _update_cron(self):
        """Update cron expression"""
        self.schedule_value = f"{self._minute} {self._hour} * * {self._day}"


class MonthlyScheduler(FluentRecurringScheduler):
    """Enhanced monthly scheduler"""

    def __init__(self):
        super().__init__("cron", "0 0 1 * *")  # 1st of month at midnight
        self._day = 1
        self._hour = 0
        self._minute = 0

    def on_day(self, day: int) -> "MonthlyScheduler":
        """Set day of month (1-31)"""
        if not 1 <= day <= 31:
            raise ValueError("Day must be between 1 and 31")
        self._day = day
        self._update_cron()
        return self

    def at(self, time: str) -> "MonthlyScheduler":
        """Set specific time"""
        try:
            self._hour, self._minute = map(int, time.split(":"))
            if not (0 <= self._hour <= 23 and 0 <= self._minute <= 59):
                raise ValueError("Invalid time format")
        except (ValueError, AttributeError):
            raise ValueError("Time must be in HH:MM format")

        self._update_cron()
        return self

    def _update_cron(self):
        """Update cron expression"""
        self.schedule_value = f"{self._minute} {self._hour} {self._day} * *"


class EnhancedRecurringManager:
    """Enhanced recurring job manager with better integration"""

    def __init__(self):
        self.jobs: Dict[str, Dict[str, Any]] = {}
        self._loaded = False

    async def load_jobs(self) -> None:
        """Load recurring jobs from the database."""
        if self._loaded:
            return

        pool = await get_context_pool()
        async with pool.acquire() as conn:
            rows = await conn.fetch(
                """
                SELECT id, job_name, schedule_type, schedule_value, priority, queue,
                       max_attempts, job_kwargs, status, created_at, last_run, next_run,
                       run_count, last_job_id
                FROM elephantq_recurring_jobs
                """
            )

        for row in rows:
            schedule_value = row["schedule_value"]
            if row["schedule_type"] == "interval":
                try:
                    schedule_value = int(schedule_value)
                except (TypeError, ValueError):
                    continue

            job_meta = get_registered_job(row["job_name"])
            job_func = job_meta["func"] if job_meta else None

            job_record = {
                "id": str(row["id"]),
                "job_name": row["job_name"],
                "job_func": job_func,
                "schedule_type": row["schedule_type"],
                "schedule_value": schedule_value,
                "priority": row["priority"],
                "queue": row["queue"],
                "max_attempts": row["max_attempts"],
                "job_kwargs": row["job_kwargs"] or {},
                "created_at": row["created_at"],
                "last_run": row["last_run"],
                "next_run": row["next_run"],
                "run_count": row["run_count"] or 0,
                "status": row["status"],
                "last_job_id": row["last_job_id"],
            }

            if job_record["next_run"] is None:
                job_record["next_run"] = self._calculate_next_run(
                    job_record["schedule_type"],
                    job_record["schedule_value"],
                    datetime.now(timezone.utc),
                )
                if job_record["next_run"] is not None:
                    await self._persist_next_run(
                        job_record["id"], job_record["next_run"]
                    )

            self.jobs[job_record["id"]] = job_record

        self._loaded = True

    async def add_recurring_job(
        self,
        job_func: Callable[..., Any],
        schedule_type: str,
        schedule_value: Union[str, int],
        priority: int = Priority.NORMAL.value,
        queue: str = "default",
        max_attempts: int = 3,
        job_kwargs: Optional[Dict[str, Any]] = None,
    ) -> str:
        """Add a recurring job with full configuration"""

        job_id = str(uuid.uuid4())
        job_kwargs = job_kwargs or {}
        job_name = f"{job_func.__module__}.{job_func.__name__}"

        try:
            json.dumps(job_kwargs)
        except TypeError as exc:
            raise ValueError("job_kwargs must be JSON-serializable") from exc

        if schedule_type == "cron":
            _require_croniter()
            if not croniter.is_valid(schedule_value):
                raise ValueError(
                    f"Invalid cron expression: {schedule_value!r}. "
                    "Expected a standard 5-field cron expression (e.g. '*/5 * * * *')."
                )

        # Create job record
        job_record = {
            "id": job_id,
            "job_name": job_name,
            "job_func": job_func,
            "schedule_type": schedule_type,
            "schedule_value": schedule_value,
            "priority": priority,
            "queue": queue,
            "max_attempts": max_attempts,
            "job_kwargs": job_kwargs,
            "created_at": datetime.now(timezone.utc),
            "last_run": None,
            "next_run": None,
            "run_count": 0,
            "status": "active",
        }

        # Calculate next run time
        if schedule_type == "interval":
            job_record["next_run"] = datetime.now(timezone.utc) + timedelta(
                seconds=int(schedule_value)
            )
        elif schedule_type == "cron":
            _require_croniter()
            cron = croniter(schedule_value, datetime.now(timezone.utc))
            job_record["next_run"] = cron.get_next(datetime)

        await self._persist_job(job_record)

        self.jobs[job_id] = job_record

        # Auto-start scheduler if it's not running
        await _ensure_scheduler_running()

        return job_id

    async def remove_job(self, job_id: str) -> bool:
        """Remove a recurring job"""
        if job_id in self.jobs:
            del self.jobs[job_id]
            await self._schedule_update(self._delete_job(job_id))
            return True
        return False

    async def pause_job(self, job_id: str) -> bool:
        """Pause a recurring job"""
        if job_id in self.jobs:
            self.jobs[job_id]["status"] = "paused"
            await self._schedule_update(self._set_status(job_id, "paused"))
            return True
        return False

    async def resume_job(self, job_id: str) -> bool:
        """Resume a paused recurring job"""
        if job_id in self.jobs:
            self.jobs[job_id]["status"] = "active"
            await self._schedule_update(self._set_status(job_id, "active"))
            return True
        return False

    async def list_jobs(self, status: Optional[str] = None) -> List[Dict[str, Any]]:
        """List recurring jobs, optionally filtered by status"""
        await self._ensure_loaded()
        jobs = list(self.jobs.values())
        if status:
            jobs = [job for job in jobs if job["status"] == status]
        return jobs

    async def get_job(self, job_id: str) -> Optional[Dict[str, Any]]:
        """Get details of a specific recurring job"""
        await self._ensure_loaded()
        return self.jobs.get(job_id)

    async def _ensure_loaded(self) -> None:
        if self._loaded:
            return
        await self.load_jobs()

    async def _schedule_update(self, coro) -> None:
        await coro

    async def _persist_job(self, job_record: Dict[str, Any]) -> None:
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            await conn.execute(
                """
                INSERT INTO elephantq_recurring_jobs (
                    id, job_name, schedule_type, schedule_value, priority, queue,
                    max_attempts, job_kwargs, status, created_at, last_run, next_run,
                    run_count, updated_at
                )
                VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), $10, $11, $12, NOW())
                """,
                uuid.UUID(job_record["id"]),
                job_record["job_name"],
                job_record["schedule_type"],
                str(job_record["schedule_value"]),
                job_record["priority"],
                job_record["queue"],
                job_record["max_attempts"],
                job_record["job_kwargs"],
                job_record["status"],
                job_record["last_run"],
                job_record["next_run"],
                job_record["run_count"],
            )

    async def _persist_next_run(self, job_id: str, next_run: datetime) -> None:
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE elephantq_recurring_jobs
                SET next_run = $1, updated_at = NOW()
                WHERE id = $2
                """,
                next_run,
                uuid.UUID(job_id),
            )

    async def _delete_job(self, job_id: str) -> None:
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            await conn.execute(
                "DELETE FROM elephantq_recurring_jobs WHERE id = $1",
                uuid.UUID(job_id),
            )

    async def _set_status(self, job_id: str, status: str) -> None:
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE elephantq_recurring_jobs
                SET status = $1, updated_at = NOW()
                WHERE id = $2
                """,
                status,
                uuid.UUID(job_id),
            )

    async def _record_run(
        self,
        job_id: str,
        last_run: datetime,
        next_run: datetime,
        run_count: int,
        last_job_id: Optional[str],
    ) -> None:
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            await conn.execute(
                """
                UPDATE elephantq_recurring_jobs
                SET last_run = $1,
                    next_run = $2,
                    run_count = $3,
                    last_job_id = $4,
                    updated_at = NOW()
                WHERE id = $5
                """,
                last_run,
                next_run,
                run_count,
                uuid.UUID(last_job_id) if last_job_id else None,
                uuid.UUID(job_id),
            )

    async def _claim_and_advance_run(
        self,
        job_id: str,
        expected_next_run: datetime,
        new_next_run: datetime,
        run_count: int,
        actual_job_id: Optional[str],
    ) -> bool:
        """
        Atomically claim a recurring job run using optimistic locking.

        Only updates if next_run still matches expected_next_run.
        If another scheduler already advanced next_run, returns False.
        This ensures multiple schedulers can run safely without coordination.
        """
        pool = await get_context_pool()
        async with pool.acquire() as conn:
            result = await conn.execute(
                """
                UPDATE elephantq_recurring_jobs
                SET last_run = NOW(),
                    next_run = $1,
                    run_count = $2,
                    last_job_id = $3,
                    updated_at = NOW()
                WHERE id = $4
                  AND next_run = $5
                """,
                new_next_run,
                run_count,
                uuid.UUID(actual_job_id) if actual_job_id else None,
                uuid.UUID(job_id),
                expected_next_run,
            )
            from elephantq.db.helpers import rows_affected

            return rows_affected(result) == 1

    def _calculate_next_run(
        self,
        schedule_type: str,
        schedule_value: Union[str, int],
        current_time: datetime,
    ) -> Optional[datetime]:
        if schedule_type == "interval":
            return current_time + timedelta(seconds=int(schedule_value))
        if schedule_type == "cron":
            _require_croniter()
            cron = croniter(schedule_value, current_time)
            return cron.get_next(datetime)  # type: ignore[no-any-return]
        return None


class EnhancedRecurringScheduler:
    """Enhanced background scheduler with better performance"""

    def __init__(self, check_interval: int = 30):
        self.check_interval = check_interval
        self.running = False
        self._task: Optional[asyncio.Task] = None

    async def start(self):
        """Start the scheduler"""
        if self.running:
            return

        self.running = True
        self._task = asyncio.create_task(self._scheduler_loop())
        logger.info(
            "Enhanced recurring scheduler started (check interval: %ds)",
            self.check_interval,
        )

    async def stop(self):
        """Stop the scheduler"""
        if not self.running:
            return

        self.running = False
        if self._task:
            self._task.cancel()
            try:
                await self._task
            except asyncio.CancelledError:
                pass
            self._task = None
        logger.info("Enhanced recurring scheduler stopped")

    async def _scheduler_loop(self):
        """Main scheduler loop with improved error handling"""
        while self.running:
            try:
                await self._process_due_jobs()
                await asyncio.sleep(self.check_interval)
            except asyncio.CancelledError:
                break
            except Exception as e:
                logger.error("Scheduler error: %s", e)
                await asyncio.sleep(min(self.check_interval, 60))  # Backoff

    async def _process_due_jobs(self):
        """Process jobs that are due to run"""
        current_time = datetime.now(timezone.utc)

        for job_id, job in _enhanced_manager.jobs.items():
            if job["status"] != "active":
                continue
            if job.get("job_func") is None:
                job_meta = get_registered_job(job.get("job_name", ""))
                if job_meta:
                    job["job_func"] = job_meta["func"]
                else:
                    continue

            try:
                if self._is_job_due(job, current_time):
                    await self._execute_job(job_id, job, current_time)
            except Exception as e:
                logger.error("Error executing recurring job %s: %s", job_id, e)

    def _is_job_due(self, job: Dict[str, Any], current_time: datetime) -> bool:
        """Check if a job is due to run"""
        next_run = job.get("next_run")
        if not next_run:
            return False

        return current_time >= next_run  # type: ignore[no-any-return]

    async def _execute_job(
        self, job_id: str, job: Dict[str, Any], current_time: datetime
    ):
        """Execute a due job with multi-scheduler safety.

        Uses optimistic locking: claim the next_run slot atomically.
        If another scheduler already claimed it, skip silently.
        """
        try:
            expected_next_run = job.get("next_run")
            if not expected_next_run:
                return

            # Calculate what next_run WILL be after this execution
            next_run = _enhanced_manager._calculate_next_run(
                job["schedule_type"], job["schedule_value"], current_time
            )
            if next_run is None:
                return

            new_run_count = job["run_count"] + 1

            # Atomically claim this run — if another scheduler already advanced
            # next_run, this returns False and we skip the enqueue.
            claimed = await _enhanced_manager._claim_and_advance_run(
                job_id=job_id,
                expected_next_run=expected_next_run,
                new_next_run=next_run,
                run_count=new_run_count,
                actual_job_id=None,  # Will update after enqueue
            )

            if not claimed:
                logger.debug(
                    "Recurring job %s already claimed by another scheduler", job_id
                )
                # Reload next_run from database to stay in sync
                job["next_run"] = next_run
                return

            # Claim succeeded — now enqueue the actual job
            actual_job_id = await enqueue(
                job["job_func"],
                priority=job["priority"],
                queue=job["queue"],
                max_attempts=job["max_attempts"],
                **job["job_kwargs"],
            )

            # Update last_job_id in DB (non-critical, best-effort)
            try:
                await _enhanced_manager._record_run(
                    job_id=job_id,
                    last_run=current_time,
                    next_run=next_run,
                    run_count=new_run_count,
                    last_job_id=actual_job_id,
                )
            except Exception:
                pass  # Claim already succeeded, job is enqueued

            # Update in-memory state
            _enhanced_manager.jobs[job_id].update(
                {
                    "last_run": current_time,
                    "run_count": new_run_count,
                    "last_job_id": actual_job_id,
                    "next_run": next_run,
                }
            )

            logger.info(
                "Recurring job %s enqueued as %s, next run: %s",
                job_id,
                actual_job_id,
                next_run,
            )

        except Exception as e:
            logger.error("Failed to execute recurring job %s: %s", job_id, e)


# Global instances
_enhanced_manager = EnhancedRecurringManager()
_enhanced_scheduler = EnhancedRecurringScheduler()

# Registry for @recurring decorated functions (avoids gc.get_objects() scan)
_decorated_recurring_jobs: List[Callable] = []


async def _ensure_scheduler_running():
    """Ensure the scheduler is running"""
    await _enhanced_manager.load_jobs()
    if not _enhanced_scheduler.running:
        await _enhanced_scheduler.start()


# ============================================================================
# IMPROVED PUBLIC API - Clean and Fluent
# ============================================================================


def every(amount: int) -> TimeIntervalBuilder:
    """
    Schedule jobs at regular intervals

    Examples:
        await every(5).minutes().schedule(cleanup_task)
        await every(2).hours().background().schedule(backup_task)
        await every(1).days().at("09:00").schedule(daily_report)
    """
    require_feature("scheduling_enabled", "Recurring scheduler")
    return TimeIntervalBuilder(amount)


def hourly() -> FluentRecurringScheduler:
    """Schedule job every hour"""
    return FluentRecurringScheduler("interval", 3600)


def daily() -> DailyScheduler:
    """
    Schedule job daily

    Examples:
        await daily().schedule(midnight_task)                    # Midnight
        await daily().at("09:00").schedule(morning_report)       # 9 AM daily
        await daily().at("15:30").high_priority().schedule(task) # 3:30 PM, high priority
    """
    require_feature("scheduling_enabled", "Recurring scheduler")
    return DailyScheduler()


def weekly() -> WeeklyScheduler:
    """
    Schedule job weekly

    Examples:
        await weekly().schedule(sunday_task)                           # Sunday midnight
        await weekly().on("monday").at("09:00").schedule(weekly_report) # Monday 9 AM
        await weekly().on(1).at("18:00").background().schedule(task)   # Monday 6 PM, background
    """
    require_feature("scheduling_enabled", "Recurring scheduler")
    return WeeklyScheduler()


def monthly() -> MonthlyScheduler:
    """
    Schedule job monthly

    Examples:
        await monthly().schedule(month_end_task)                        # 1st midnight
        await monthly().on_day(15).at("12:00").schedule(mid_month)      # 15th at noon
        await monthly().on_day(1).at("09:00").urgent().schedule(task)  # 1st at 9 AM, urgent
    """
    require_feature("scheduling_enabled", "Recurring scheduler")
    return MonthlyScheduler()


def cron(expression: str) -> FluentRecurringScheduler:
    """
    Schedule job using cron expression

    Examples:
        await cron("*/15 * * * *").schedule(every_15_min)         # Every 15 minutes
        await cron("0 9 * * 1-5").high_priority().schedule(task) # Weekdays 9 AM, high priority
    """
    require_feature("scheduling_enabled", "Recurring scheduler")
    return FluentRecurringScheduler("cron", expression)


# Priority convenience functions
def high_priority() -> FluentRecurringScheduler:
    """Create high priority job (convenience method)"""
    scheduler = FluentRecurringScheduler("interval", 0)  # Will be overridden
    return scheduler.high_priority()


def background() -> FluentRecurringScheduler:
    """Create background priority job (convenience method)"""
    scheduler = FluentRecurringScheduler("interval", 0)  # Will be overridden
    return scheduler.background()


def urgent() -> FluentRecurringScheduler:
    """Create urgent priority job (convenience method)"""
    scheduler = FluentRecurringScheduler("interval", 0)  # Will be overridden
    return scheduler.urgent()


# Management functions
async def start_recurring_scheduler(check_interval: int = 30):
    """Start the global recurring job scheduler"""
    _enhanced_scheduler.check_interval = check_interval
    await _enhanced_scheduler.start()


async def stop_recurring_scheduler():
    """Stop the global recurring job scheduler"""
    await _enhanced_scheduler.stop()


def get_recurring_manager() -> EnhancedRecurringManager:
    """Get the global recurring job manager"""
    return _enhanced_manager


def get_recurring_scheduler() -> EnhancedRecurringScheduler:
    """Get the global recurring job scheduler"""
    return _enhanced_scheduler


async def list_recurring_jobs(status: Optional[str] = None) -> List[Dict[str, Any]]:
    """List all recurring jobs"""
    return await _enhanced_manager.list_jobs(status=status)


async def get_recurring_job(job_id: str) -> Optional[Dict[str, Any]]:
    """Get details of a specific recurring job"""
    return await _enhanced_manager.get_job(job_id)


async def remove_recurring_job(job_id: str) -> bool:
    """Remove a recurring job"""
    return await _enhanced_manager.remove_job(job_id)


async def pause_recurring_job(job_id: str) -> bool:
    """Pause a recurring job"""
    return await _enhanced_manager.pause_job(job_id)


async def resume_recurring_job(job_id: str) -> bool:
    """Resume a paused recurring job"""
    return await _enhanced_manager.resume_job(job_id)


def get_scheduler_status() -> Dict[str, Any]:
    """Get detailed scheduler status"""
    return {
        "running": _enhanced_scheduler.running,
        "check_interval": _enhanced_scheduler.check_interval,
        "active_jobs": len(
            [j for j in _enhanced_manager.jobs.values() if j["status"] == "active"]
        ),
        "paused_jobs": len(
            [j for j in _enhanced_manager.jobs.values() if j["status"] == "paused"]
        ),
        "total_jobs": len(_enhanced_manager.jobs),
    }


# ============================================================================
# DECORATOR SUPPORT
# ============================================================================


def recurring(schedule_expr: str, **config):
    """
    Decorator for recurring jobs

    Examples:
        @recurring("*/15 * * * *")  # Every 15 minutes
        async def health_check():
            pass

        @recurring("1h", priority="high", queue="urgent")  # Every hour, high priority
        async def urgent_cleanup():
            pass
    """

    def decorator(func):
        # Register for later scheduling via schedule_decorated_jobs()
        _decorated_recurring_jobs.append(func)

        # Determine schedule type and create appropriate scheduler
        if " " in schedule_expr and len(schedule_expr.split()) == 5:
            # Cron expression
            scheduler = cron(schedule_expr)
        else:
            # Try to parse as interval
            try:
                if schedule_expr.endswith(("s", "m", "h", "d")):
                    unit = schedule_expr[-1]
                    amount = int(schedule_expr[:-1])

                    unit_map = {
                        "s": "seconds",
                        "m": "minutes",
                        "h": "hours",
                        "d": "days",
                    }
                    scheduler = getattr(every(amount), unit_map[unit])()
                else:
                    raise ValueError("Invalid schedule expression")
            except (ValueError, AttributeError):
                # Fallback to cron
                scheduler = cron(schedule_expr)

        # Apply configuration
        if "priority" in config:
            scheduler = scheduler.priority(config["priority"])
        if "queue" in config:
            scheduler = scheduler.queue(config["queue"])
        if "max_attempts" in config:
            scheduler = scheduler.max_attempts(config["max_attempts"])

        # Store configuration for later scheduling
        func._recurring_config = {"scheduler": scheduler, "config": config}

        return func

    return decorator


async def schedule_decorated_jobs():
    """Schedule all functions decorated with @recurring"""
    scheduled_count = 0
    for func in _decorated_recurring_jobs:
        config = func._recurring_config
        job_id = await config["scheduler"].schedule(func)
        logger.info("Scheduled decorated job %s as %s", func.__name__, job_id)
        scheduled_count += 1

    return scheduled_count
