// Unlicense — cochranblock.org
// Contributors: Mattbusel (XFactor), GotEmCoach, KOVA, Claude Opus 4.6, SuperNinja, Composer 1.5, Google Gemini Pro 3

// Generated by: kova micro run f80 (structure), human-corrected API calls
//! pipe — Full micro-model pipeline: classify → route → run → validate.
//! One command, end-to-end. The micro equivalent of `kova factory`.

use std::time::{Duration, Instant};

use super::registry::T149;
use super::router::{f243, f242};
use super::runner::{f244, T156, T155};
use super::validate::{f263, T173};
use crate::cluster::T193;

/// T148=PipeResult
/// Full pipeline result.
#[derive(Debug)]
pub struct T148 {
    /// What the classifier said.
    pub classification: String,
    /// Which template was selected.
    pub template_id: String,
    /// Template human name.
    pub template_name: String,
    /// Raw model response.
    pub response: String,
    /// Validation verdict.
    pub validation: T173,
    /// Node that handled the main run.
    pub node_id: String,
    /// Time for classification step.
    pub classify_duration: Duration,
    /// Time for main run step.
    pub run_duration: Duration,
    /// Total wall time.
    pub total_duration: Duration,
}

/// f240=run_pipe
/// Run the full pipeline: classify → route → run → validate.
pub fn f240(
    input: &str,
    registry: &T149,
    cluster: &T193,
) -> Result<T148, String> {
    let total_start = Instant::now();
    let breaker = T155::new(3);
    let budget = T156::new(100_000);

    // T182 1: Classify via f79 (or keyword fallback if no nodes)
    let classify_start = Instant::now();
    let classification = match registry.get("f79") {
        Some(tmpl) => {
            match f244(tmpl, input, cluster, &breaker, &budget) {
                Ok(result) => result.response.trim().to_lowercase(),
                Err(_) => {
                    // Fallback to keyword classification
                    f242(input)
                }
            }
        }
        None => f242(input),
    };
    let classify_duration = classify_start.elapsed();

    // T182 2: Map classification to template
    let template_id = f243(&classification);
    let tmpl = registry
        .get(&template_id)
        .ok_or_else(|| format!("no template for category: {}", classification))?;

    // T182 3: Run the template
    let run_start = Instant::now();
    let result = f244(tmpl, input, cluster, &breaker, &budget)?;
    let run_duration = run_start.elapsed();

    // T182 4: Validate
    let validation = f263(&result, input, &tmpl.output_schema);

    let total_duration = total_start.elapsed();

    Ok(T148 {
        classification,
        template_id,
        template_name: tmpl.name.clone(),
        response: result.response,
        validation,
        node_id: result.node_id,
        classify_duration,
        run_duration,
        total_duration,
    })
}

/// f241=print_pipe_result
/// Print a pipe result in human-readable format.
pub fn f241(r: &T148) {
    println!("{}", r.response);
    eprintln!("──────────────────────────────────────────");
    eprintln!(
        "[pipe] classify: {} → {} ({})",
        r.classification, r.template_id, r.template_name
    );
    eprintln!("[pipe] node: {}", r.node_id);
    eprintln!(
        "[pipe] timing: classify {:.1}s, run {:.1}s, total {:.1}s",
        r.classify_duration.as_secs_f64(),
        r.run_duration.as_secs_f64(),
        r.total_duration.as_secs_f64()
    );
    eprintln!(
        "[pipe] validation: {} (confidence: {:.0}%)",
        r.validation.summary,
        r.validation.confidence * 100.0
    );
}