"""Tests for job management CLI commands."""

from datetime import datetime, timezone
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from typer.testing import CliRunner

from fliiq.cli.jobs import job_app
from fliiq.runtime.scheduler.loader import load_job, save_job
from fliiq.runtime.scheduler.models import (
    JobDefinition,
    RunLogEntry,
    TriggerConfig,
)
from fliiq.runtime.scheduler.run_log import save_run_log

runner = CliRunner()


def _make_job(name: str = "test-job", schedule: str = "0 9 * * *") -> JobDefinition:
    return JobDefinition(
        name=name,
        trigger=TriggerConfig(type="cron", schedule=schedule),
        prompt="Test prompt",
    )


@pytest.fixture()
def jobs_env(tmp_path, monkeypatch):
    """Set up a tmp project with .fliiq/jobs/."""
    jobs_dir = tmp_path / ".fliiq" / "jobs"
    jobs_dir.mkdir(parents=True)
    monkeypatch.chdir(tmp_path)
    return jobs_dir


# --- list ---


def test_job_list_empty(jobs_env):
    result = runner.invoke(job_app, ["list"])
    assert result.exit_code == 0
    assert "No jobs" in result.output


def test_job_list_with_jobs(jobs_env):
    save_job(_make_job("alpha-job"), jobs_env)
    save_job(_make_job("beta-job"), jobs_env)

    result = runner.invoke(job_app, ["list"])
    assert result.exit_code == 0
    assert "alpha-job" in result.output
    assert "beta-job" in result.output


# --- create ---


def test_job_create(jobs_env):
    result = runner.invoke(job_app, [
        "create", "my-job", "Do stuff",
        "--trigger-type", "cron", "--schedule", "0 9 * * *",
    ])
    assert result.exit_code == 0
    assert "created" in result.output
    assert (jobs_env / "my-job.yaml").exists()

    job = load_job(jobs_env / "my-job.yaml")
    assert job.name == "my-job"
    assert job.prompt == "Do stuff"
    assert job.trigger.type == "cron"


def test_job_create_invalid_name(jobs_env):
    result = runner.invoke(job_app, [
        "create", "INVALID NAME", "Do stuff",
        "--trigger-type", "cron", "--schedule", "0 9 * * *",
    ])
    assert result.exit_code == 1


def test_job_create_missing_schedule(jobs_env):
    result = runner.invoke(job_app, [
        "create", "no-sched", "Do stuff",
        "--trigger-type", "cron",
    ])
    assert result.exit_code == 1
    assert "schedule" in result.output.lower()


# --- show ---


def test_job_show(jobs_env):
    save_job(_make_job("show-me"), jobs_env)

    result = runner.invoke(job_app, ["show", "show-me"])
    assert result.exit_code == 0
    assert "show-me" in result.output
    assert "cron" in result.output


def test_job_show_not_found(jobs_env):
    result = runner.invoke(job_app, ["show", "nonexistent"])
    assert result.exit_code == 1
    assert "not found" in result.output.lower()


# --- logs ---


def test_job_logs_empty(jobs_env):
    result = runner.invoke(job_app, ["logs", "no-logs"])
    assert result.exit_code == 0
    assert "No run logs" in result.output


def test_job_logs_with_entries(jobs_env):
    save_job(_make_job("logged-job"), jobs_env)
    entry = RunLogEntry(
        job_name="logged-job",
        started_at=datetime.now(timezone.utc),
        completed_at=datetime.now(timezone.utc),
        status="success",
        duration_ms=1500,
        iterations=3,
        stop_reason="end_turn",
    )
    save_run_log(entry, jobs_env)

    result = runner.invoke(job_app, ["logs", "logged-job"])
    assert result.exit_code == 0
    assert "success" in result.output


# --- delete ---


def test_job_delete(jobs_env):
    save_job(_make_job("del-me"), jobs_env)
    assert (jobs_env / "del-me.yaml").exists()

    result = runner.invoke(job_app, ["delete", "del-me", "--yes"])
    assert result.exit_code == 0
    assert "deleted" in result.output
    assert not (jobs_env / "del-me.yaml").exists()


def test_job_delete_nonexistent(jobs_env):
    result = runner.invoke(job_app, ["delete", "ghost", "--yes"])
    assert result.exit_code == 1
    assert "not found" in result.output.lower()


# --- run ---


def test_job_run(jobs_env):
    save_job(_make_job("run-me"), jobs_env)

    mock_entry = RunLogEntry(
        job_name="run-me",
        started_at=datetime.now(timezone.utc),
        completed_at=datetime.now(timezone.utc),
        status="success",
        duration_ms=200,
        iterations=1,
        stop_reason="end_turn",
    )

    with (
        patch("fliiq.runtime.agent.setup.resolve_llm_config", return_value=MagicMock()),
        patch("fliiq.runtime.scheduler.executor.execute_job", new_callable=AsyncMock, return_value=mock_entry),
    ):
        result = runner.invoke(job_app, ["run", "run-me"])

    assert result.exit_code == 0
    assert "success" in result.output.lower()
