"""Job management CLI commands."""

import asyncio
from pathlib import Path

import typer
from pydantic import ValidationError

from fliiq.cli import display
from fliiq.runtime.scheduler.loader import delete_job, load_job, load_jobs, save_job
from fliiq.runtime.scheduler.models import JobDefinition, TriggerConfig
from fliiq.runtime.scheduler.run_log import load_run_logs

job_app = typer.Typer(help="Manage scheduled jobs")


def _jobs_dir() -> Path:
    from fliiq.runtime.config import resolve_fliiq_dir

    try:
        return resolve_fliiq_dir(require_local=True) / "jobs"
    except FileNotFoundError:
        display.print_error("Jobs require a local .fliiq/ directory. Run `fliiq init --project` first.")
        raise typer.Exit(1)


@job_app.command("list")
def list_jobs():
    """List all jobs."""
    jobs = load_jobs(_jobs_dir())
    if not jobs:
        display.console.print("No jobs found. Create one with: fliiq job create <name> <prompt>")
        return

    rows = []
    for j in jobs:
        last_run = j.state.last_run_at.strftime("%Y-%m-%d %H:%M") if j.state.last_run_at else "-"
        rows.append([
            j.name,
            j.trigger.type,
            j.trigger.schedule or j.trigger.source or "-",
            "yes" if j.enabled else "no",
            j.state.last_status or "-",
            last_run,
            str(j.state.run_count),
        ])

    display.print_table(
        ["Name", "Trigger", "Schedule", "Enabled", "Status", "Last Run", "Runs"],
        rows,
        title="Jobs",
    )


@job_app.command("create")
def create_job(
    name: str = typer.Argument(..., help="Job name (lowercase, hyphens, e.g. daily-summary)"),
    prompt: str = typer.Argument(..., help="Prompt for the agent"),
    trigger_type: str = typer.Option("cron", "--trigger-type", "-t", help="cron, at, every, or webhook"),
    schedule: str = typer.Option(None, "--schedule", "-s", help="Schedule expression"),
    source: str = typer.Option(None, "--source", help="Webhook source (for webhook trigger)"),
    skills: str = typer.Option(None, "--skills", help="Comma-separated skill names"),
    enabled: bool = typer.Option(True, "--enabled/--disabled", help="Enable/disable the job"),
):
    """Create a new job definition."""
    if trigger_type in ("cron", "at", "every") and not schedule:
        display.print_error(f"Trigger type '{trigger_type}' requires --schedule")
        raise typer.Exit(1)
    if trigger_type == "webhook" and not source:
        display.print_error("Trigger type 'webhook' requires --source")
        raise typer.Exit(1)

    try:
        trigger = TriggerConfig(type=trigger_type, schedule=schedule, source=source)
        job = JobDefinition(
            name=name,
            trigger=trigger,
            prompt=prompt,
            skills=skills.split(",") if skills else [],
            enabled=enabled,
        )
    except ValidationError as e:
        display.print_error(str(e))
        raise typer.Exit(1)

    save_job(job, _jobs_dir())
    display.console.print(f"Job '{name}' created.")


@job_app.command("show")
def show_job(name: str = typer.Argument(..., help="Job name")):
    """Show details of a job."""
    path = _jobs_dir() / f"{name}.yaml"
    if not path.is_file():
        display.print_error(f"Job '{name}' not found.")
        raise typer.Exit(1)

    job = load_job(path)
    display.console.print(f"[bold]Name:[/bold]     {job.name}")
    display.console.print(f"[bold]Trigger:[/bold]  {job.trigger.type}")
    display.console.print(f"[bold]Schedule:[/bold] {job.trigger.schedule or job.trigger.source or '-'}")
    display.console.print(f"[bold]Prompt:[/bold]   {job.prompt}")
    display.console.print(f"[bold]Skills:[/bold]   {', '.join(job.skills) if job.skills else '-'}")
    display.console.print(f"[bold]Enabled:[/bold]  {'yes' if job.enabled else 'no'}")
    display.console.print(f"[bold]Runs:[/bold]     {job.state.run_count}")
    display.console.print(f"[bold]Status:[/bold]   {job.state.last_status or '-'}")
    last_run = job.state.last_run_at.strftime("%Y-%m-%d %H:%M") if job.state.last_run_at else "-"
    display.console.print(f"[bold]Last Run:[/bold] {last_run}")


@job_app.command("logs")
def job_logs(
    name: str = typer.Argument(..., help="Job name"),
    limit: int = typer.Option(10, "--limit", "-n", help="Number of recent logs"),
):
    """Show run history for a job."""
    entries = load_run_logs(name, _jobs_dir(), limit=limit)
    if not entries:
        display.console.print(f"No run logs for '{name}'.")
        return

    rows = []
    for e in entries:
        ts = e.started_at.strftime("%Y-%m-%d %H:%M:%S")
        dur = f"{e.duration_ms / 1000:.1f}s" if e.duration_ms else "-"
        preview = (e.response_text[:80] + "...") if len(e.response_text) > 80 else (e.response_text or "-")
        preview = preview.replace("\n", " ")
        rows.append([ts, e.status, dur, str(e.iterations), preview])

    display.print_table(
        ["Started", "Status", "Duration", "Iterations", "Response"],
        rows,
        title=f"Run Logs: {name}",
    )


@job_app.command("output")
def job_output(
    name: str = typer.Argument(..., help="Job name"),
    run: int = typer.Option(1, "--run", "-r", help="Which run (1=latest, 2=second latest, etc.)"),
):
    """Show the full response from a job run."""
    entries = load_run_logs(name, _jobs_dir(), limit=run)
    if not entries or len(entries) < run:
        display.print_error(f"No run #{run} found for '{name}'.")
        raise typer.Exit(1)

    entry = entries[run - 1]
    if not entry.response_text:
        display.console.print(f"Run at {entry.started_at} had no response text.")
        return

    display.console.print(f"[bold]Job:[/bold] {name}")
    display.console.print(f"[bold]Run:[/bold] {entry.started_at.strftime('%Y-%m-%d %H:%M:%S')}")
    display.console.print(f"[bold]Status:[/bold] {entry.status}")
    display.console.print()
    display.print_markdown(entry.response_text)


@job_app.command("delete")
def delete_job_cmd(
    name: str = typer.Argument(..., help="Job name"),
    yes: bool = typer.Option(False, "--yes", "-y", help="Skip confirmation"),
):
    """Delete a job definition."""
    path = _jobs_dir() / f"{name}.yaml"
    if not path.is_file():
        display.print_error(f"Job '{name}' not found.")
        raise typer.Exit(1)

    if not yes:
        typer.confirm(f"Delete job '{name}'?", abort=True)

    delete_job(name, _jobs_dir())
    display.console.print(f"Job '{name}' deleted.")


@job_app.command("run")
def run_job(name: str = typer.Argument(..., help="Job name")):
    """Run a job immediately (inline, no daemon needed)."""
    from fliiq.runtime.agent.setup import resolve_llm_config
    from fliiq.runtime.scheduler.executor import execute_job

    path = _jobs_dir() / f"{name}.yaml"
    if not path.is_file():
        display.print_error(f"Job '{name}' not found.")
        raise typer.Exit(1)

    job = load_job(path)

    try:
        llm_config = resolve_llm_config()
    except RuntimeError as e:
        display.print_error(str(e))
        raise typer.Exit(1)

    display.console.print(f"Running job '{name}'...")
    entry = asyncio.run(execute_job(job, _jobs_dir(), _jobs_dir().parent.parent, llm_config))

    display.console.print(f"Status: {entry.status}")
    display.console.print(f"Duration: {entry.duration_ms}ms")
    display.console.print(f"Iterations: {entry.iterations}")
    if entry.error:
        display.print_error(f"Error: {entry.error}")
