"""CLI commands for the scheduler.

Provides commands for managing cron-based recurring jobs.
"""

from __future__ import annotations

import logging
import time
from pathlib import Path

import click

from oclawma.cli_ui import (
    accent,
    header,
    highlight,
    muted,
    print_error,
    print_success,
    print_warning,
)
from oclawma.scheduler import CronError, validate_cron

logger = logging.getLogger(__name__)


@click.group(name="scheduler")
def scheduler_cli():
    """Manage cron-based recurring jobs.

    Schedule and manage jobs that run on a recurring basis using cron expressions.

    \b
    Examples:
        oclawma scheduler add --cron "0 0 * * *" --payload '{"task": "backup"}'
        oclawma scheduler list
        oclawma scheduler run --daemon
    """
    pass


@scheduler_cli.command(name="add")
@click.option(
    "--cron",
    required=True,
    help="Cron expression (e.g., '0 0 * * *' for daily at midnight)",
)
@click.option(
    "--payload",
    required=True,
    help="Job payload as JSON string",
)
@click.option(
    "--timezone",
    default="UTC",
    help="Timezone for scheduling (default: UTC)",
)
@click.option(
    "--priority",
    type=click.Choice(["CRITICAL", "HIGH", "NORMAL", "LOW"]),
    default="NORMAL",
    help="Job priority",
)
@click.option(
    "--db-path",
    type=click.Path(),
    default="~/.oclawma/queue.db",
    help="Path to queue database",
)
def add_job(cron: str, payload: str, timezone: str, priority: str, db_path: str):
    """Add a new recurring job."""
    import json

    from oclawma.queue import JobPriority, JobQueue, schedule_recurring_job

    # Validate cron expression
    if not validate_cron(cron):
        print_error(f"Invalid cron expression: {cron}")
        raise click.ClickException("Invalid cron expression")

    # Parse payload
    try:
        payload_dict = json.loads(payload)
    except json.JSONDecodeError as e:
        print_error(f"Invalid JSON payload: {e}")
        raise click.ClickException("Invalid JSON payload") from e

    # Map priority string to enum
    priority_map = {
        "CRITICAL": JobPriority.CRITICAL,
        "HIGH": JobPriority.HIGH,
        "NORMAL": JobPriority.NORMAL,
        "LOW": JobPriority.LOW,
    }
    job_priority = priority_map[priority]

    # Expand db path
    db_path = Path(db_path).expanduser()
    db_path.parent.mkdir(parents=True, exist_ok=True)

    try:
        with JobQueue(db_path) as queue:
            job = schedule_recurring_job(
                queue=queue,
                payload=payload_dict,
                cron_expression=cron,
                timezone=timezone,
                priority=job_priority,
            )

        print_success(f"Scheduled recurring job {job.id}")
        click.echo(f"  Cron: {highlight(cron)}")
        click.echo(f"  Timezone: {timezone}")
        click.echo(f"  Next run: {job.next_run_at}")
        click.echo(f"  Priority: {priority}")

    except CronError as e:
        print_error(f"Failed to schedule job: {e}")
        raise click.ClickException(str(e)) from e
    except Exception as e:
        print_error(f"Failed to schedule job: {e}")
        raise click.ClickException(str(e)) from e


@scheduler_cli.command(name="list")
@click.option(
    "--db-path",
    type=click.Path(),
    default="~/.oclawma/queue.db",
    help="Path to queue database",
)
def list_jobs(db_path: str):
    """List all recurring jobs."""
    from oclawma.queue import JobQueue

    db_path = Path(db_path).expanduser()

    if not db_path.exists():
        click.echo("No jobs found (database does not exist)")
        return

    with JobQueue(db_path) as queue:
        jobs = queue.list_jobs()
        recurring_jobs = [j for j in jobs if j.cron_expression]

        if not recurring_jobs:
            click.echo("No recurring jobs found")
            return

        header("Recurring Jobs")
        for job in recurring_jobs:
            click.echo(f"\n• Job {accent(f'#{job.id}')} ({job.status.value})")
            click.echo(f"  Cron: {highlight(job.cron_expression)}")
            click.echo(f"  Timezone: {job.timezone}")
            click.echo(f"  Next run: {job.next_run_at or 'Not scheduled'}")
            click.echo(f"  Priority: {job.priority.name}")
            click.echo(f"  Payload: {muted(str(job.payload))}")


@scheduler_cli.command(name="remove")
@click.argument("job-id", type=int)
@click.option(
    "--db-path",
    type=click.Path(),
    default="~/.oclawma/queue.db",
    help="Path to queue database",
)
def remove_job(job_id: int, db_path: str):
    """Remove a recurring job."""
    from oclawma.queue import JobNotFoundError, JobQueue

    db_path = Path(db_path).expanduser()

    if not db_path.exists():
        print_error("Database does not exist")
        raise click.ClickException("Database does not exist")

    with JobQueue(db_path) as queue:
        try:
            job = queue.get_job(job_id)
            if not job.cron_expression:
                print_warning(f"Job {job_id} is not a recurring job")
                return

            queue.cancel(job_id)
            print_success(f"Removed recurring job {job_id}")
        except JobNotFoundError as e:
            print_error(f"Job {job_id} not found")
            raise click.ClickException(f"Job {job_id} not found") from e


@scheduler_cli.command(name="run")
@click.option(
    "--db-path",
    type=click.Path(),
    default="~/.oclawma/queue.db",
    help="Path to queue database",
)
@click.option(
    "--daemon",
    is_flag=True,
    help="Run as a daemon (continuously process jobs)",
)
@click.option(
    "--interval",
    default=60,
    help="Polling interval in seconds (default: 60)",
)
def run_scheduler(db_path: str, daemon: bool, interval: int):
    """Run the scheduler to process due jobs.

    In daemon mode, continuously polls for due jobs and processes them.
    Without daemon mode, processes all currently due jobs and exits.
    """
    import signal
    import sys

    from oclawma.queue import JobQueue, process_due_jobs

    db_path = Path(db_path).expanduser()
    db_path.parent.mkdir(parents=True, exist_ok=True)

    # Setup signal handlers for graceful shutdown
    def signal_handler(sig, frame):
        click.echo("\nShutting down scheduler...")
        sys.exit(0)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    def handle_job(job):
        """Process a single job."""
        click.echo(f"Processing job {job.id}: {job.payload}")
        # In a real implementation, this would dispatch to the appropriate handler
        # For now, just log that we would process it
        logger.info(f"Would process job {job.id} with payload {job.payload}")

    if daemon:
        header(f"Starting scheduler daemon (interval: {interval}s)")
        click.echo(f"Database: {db_path}")
        click.echo("Press Ctrl+C to stop\n")

        with JobQueue(db_path) as queue:
            while True:
                try:
                    count = process_due_jobs(queue, handle_job)
                    if count > 0:
                        click.echo(f"Processed {count} due jobs")
                    time.sleep(interval)
                except Exception as e:
                    logger.error(f"Error in scheduler loop: {e}")
                    time.sleep(interval)
    else:
        # One-shot mode
        header("Running scheduler (one-shot mode)")

        with JobQueue(db_path) as queue:
            count = process_due_jobs(queue, handle_job)

        if count > 0:
            print_success(f"Processed {count} due jobs")
        else:
            click.echo("No due jobs found")


@scheduler_cli.command(name="validate")
@click.argument("expression")
def validate_cron_cmd(expression: str):
    """Validate a cron expression."""
    if validate_cron(expression):
        print_success(f"Valid cron expression: {expression}")
    else:
        print_error(f"Invalid cron expression: {expression}")
        raise click.ClickException("Invalid cron expression")
