use std::future::Future;

use chrono::{DateTime, Utc};
use zeroclaw::config::Config as ZeroClawConfig;
use zeroclaw::cron::{self, CronJob, CronRun, JobType, Schedule, SessionTarget};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CronExecutionResult {
    pub job_id: String,
    pub success: bool,
    pub output: String,
}

pub fn configure_embedded_cron(config: &mut ZeroClawConfig) {
    config.cron.enabled = true;
    config.cron.catch_up_on_startup = false;
    config.scheduler.enabled = false;
    config.scheduler.max_concurrent = 1;
    config.scheduler.max_tasks = config.scheduler.max_tasks.max(1);
}

pub fn add_agent_job(
    config: &ZeroClawConfig,
    name: Option<String>,
    schedule: Schedule,
    prompt: &str,
    allowed_tools: Option<Vec<String>>,
) -> anyhow::Result<CronJob> {
    cron::add_agent_job(
        config,
        name,
        schedule,
        prompt,
        SessionTarget::Isolated,
        None,
        None,
        false,
        allowed_tools,
    )
}

pub fn list_jobs(config: &ZeroClawConfig) -> anyhow::Result<Vec<CronJob>> {
    cron::list_jobs(config)
}

pub fn list_runs(
    config: &ZeroClawConfig,
    job_id: &str,
    limit: usize,
) -> anyhow::Result<Vec<CronRun>> {
    cron::list_runs(config, job_id, limit)
}

pub async fn run_due_jobs<F, Fut>(
    config: &ZeroClawConfig,
    now: DateTime<Utc>,
    mut runner: F,
) -> anyhow::Result<Vec<CronExecutionResult>>
where
    F: FnMut(&CronJob) -> Fut,
    Fut: Future<Output = anyhow::Result<String>>,
{
    let jobs = cron::due_jobs(config, now)?;
    let mut results = Vec::with_capacity(jobs.len());

    for job in jobs {
        if !matches!(job.job_type, JobType::Agent) {
            anyhow::bail!(
                "unsupported cron job type in sgclaw compat: {:?}",
                job.job_type
            );
        }

        let started_at = Utc::now();
        let (success, output) = match runner(&job).await {
            Ok(output) => (true, output),
            Err(err) => (false, err.to_string()),
        };
        let finished_at = Utc::now();
        let duration_ms = (finished_at - started_at).num_milliseconds();

        cron::record_run(
            config,
            &job.id,
            started_at,
            finished_at,
            if success { "ok" } else { "error" },
            Some(&output),
            duration_ms,
        )?;
        cron::reschedule_after_run(config, &job, success, &output)?;

        results.push(CronExecutionResult {
            job_id: job.id,
            success,
            output,
        });
    }

    Ok(results)
}
