rok-cli 0.6.1

Developer CLI for rok-based Axum applications
//! `rok schedule:list` — list registered cron jobs from source files.

use std::{fs, path::Path};

pub fn run() -> anyhow::Result<()> {
    let schedule_path = Path::new("src/console/schedule.rs");
    if !schedule_path.exists() {
        println!("  (no src/console/schedule.rs found)");
        return Ok(());
    }

    let src = fs::read_to_string(schedule_path)?;

    println!("{:<30} {:<20} {:<12} CRON", "NAME", "QUEUE", "FREQUENCY");
    println!("{}", "-".repeat(90));

    let mut found = false;

    for line in src.lines() {
        let trimmed = line.trim();

        // Match: .every_minute(), .daily(), .hourly(), .daily_at("14:00"), etc.
        let frequency = if trimmed.contains(".every_minute(") {
            Some("every_minute")
        } else if trimmed.contains(".every_second(") {
            Some("every_second")
        } else if trimmed.contains(".hourly(") {
            Some("hourly")
        } else if trimmed.contains(".daily(") {
            Some("daily")
        } else if trimmed.contains(".daily_at(") {
            Some("daily_at")
        } else if trimmed.contains(".weekly_on(") {
            Some("weekly_on")
        } else if trimmed.contains(".monthly_on(") {
            Some("monthly_on")
        } else if trimmed.contains(".cron(") {
            Some("cron")
        } else if trimmed.contains(".every_n_minutes(") {
            Some("every_n_min")
        } else {
            None
        };

        if let Some(freq) = frequency {
            // Try to extract the name from the comment or callback
            let name = extract_name(trimmed);
            let queue = extract_queue(trimmed);
            let cron_expr = extract_cron_expr(trimmed, freq);

            println!("{:<30} {:<20} {:<12} {}", name, queue, freq, cron_expr);
            found = true;
        }
    }

    if !found {
        println!("  (no scheduled jobs found in src/console/schedule.rs)");
    }

    Ok(())
}

fn extract_name(line: &str) -> String {
    // Look for name in comments: // "JobName"
    if let Some(comment_pos) = line.find("//") {
        let comment = line[comment_pos + 2..].trim().trim_matches('"');
        if !comment.is_empty() {
            return comment.to_string();
        }
    }
    // Fallback: use a hash of the line
    let hash = line.len().to_string();
    format!("task_{}", &hash)
}

fn extract_queue(line: &str) -> String {
    if line.contains("queue") {
        if let Some(start) = line.find("queue = \"") {
            let rest = &line[start + 9..];
            if let Some(end) = rest.find('"') {
                return rest[..end].to_string();
            }
        }
    }
    "default".to_string()
}

fn extract_cron_expr(line: &str, frequency: &str) -> String {
    // Extract the argument inside parentheses
    if let Some(paren_start) = line.find('(') {
        let after_paren = &line[paren_start + 1..];
        if let Some(paren_end) = after_paren.find(')') {
            let args = after_paren[..paren_end].trim();
            if !args.is_empty() && frequency != "cron" {
                return args.to_string();
            }
        }
    }
    // If it's a cron expression, extract it
    if frequency == "cron" {
        if let Some(start) = line.find(".cron(\"") {
            let rest = &line[start + 7..];
            if let Some(end) = rest.find('"') {
                return rest[..end].to_string();
            }
        }
        return "custom".to_string();
    }
    String::new()
}