#![allow(dead_code)]
pub mod keys;
pub mod models;
pub mod schema;

#[allow(unused_imports)]
pub use models::*;
#[allow(unused_imports)]
pub use schema::*;

pub fn create_business_logic(
    db: &CozoDb,
    element_qualified: &str,
    description: &str,
    user_story_id: Option<&str>,
    feature_id: Option<&str>,
) -> Result<models::BusinessLogic, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] <- [[ $eq, $desc, $us, $feat ]] :put business_logic { element_qualified, description, user_story_id, feature_id }"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "eq".to_string(),
        serde_json::Value::String(element_qualified.to_string()),
    );
    params.insert(
        "desc".to_string(),
        serde_json::Value::String(description.to_string()),
    );
    params.insert(
        "us".to_string(),
        user_story_id
            .map(|s| serde_json::Value::String(s.to_string()))
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "feat".to_string(),
        feature_id
            .map(|s| serde_json::Value::String(s.to_string()))
            .unwrap_or(serde_json::Value::Null),
    );

    db.run_script(query, params)?;

    Ok(models::BusinessLogic {
        id: None,
        element_qualified: element_qualified.to_string(),
        description: description.to_string(),
        user_story_id: user_story_id.map(String::from),
        feature_id: feature_id.map(String::from),
    })
}

pub fn get_business_logic(
    db: &CozoDb,
    element_qualified: &str,
) -> Result<Option<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id], element_qualified = $eq"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "eq".to_string(),
        serde_json::Value::String(element_qualified.to_string()),
    );

    let result = db.run_script(query, params)?;
    let rows = result.rows;

    if rows.is_empty() {
        return Ok(None);
    }

    let row = &rows[0];
    let user_story_id = row[2].as_str().map(String::from);
    let feature_id = row[3].as_str().map(String::from);

    Ok(Some(models::BusinessLogic {
        id: None,
        element_qualified: row[0].as_str().unwrap_or("").to_string(),
        description: row[1].as_str().unwrap_or("").to_string(),
        user_story_id,
        feature_id,
    }))
}

pub fn update_business_logic(
    db: &CozoDb,
    element_qualified: &str,
    description: &str,
    user_story_id: Option<&str>,
    feature_id: Option<&str>,
) -> Result<Option<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] <- [[ $eq, $desc, $us, $feat ]] :put business_logic { element_qualified, description, user_story_id, feature_id }"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "eq".to_string(),
        serde_json::Value::String(element_qualified.to_string()),
    );
    params.insert(
        "desc".to_string(),
        serde_json::Value::String(description.to_string()),
    );
    params.insert(
        "us".to_string(),
        user_story_id
            .map(|s| serde_json::Value::String(s.to_string()))
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "feat".to_string(),
        feature_id
            .map(|s| serde_json::Value::String(s.to_string()))
            .unwrap_or(serde_json::Value::Null),
    );

    db.run_script(query, params)?;

    Ok(Some(models::BusinessLogic {
        id: None,
        element_qualified: element_qualified.to_string(),
        description: description.to_string(),
        user_story_id: user_story_id.map(String::from),
        feature_id: feature_id.map(String::from),
    }))
}

#[allow(dead_code)]
pub fn delete_business_logic(
    db: &CozoDb,
    element_qualified: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let query = r#":delete business_logic where element_qualified = $eq"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "eq".to_string(),
        serde_json::Value::String(element_qualified.to_string()),
    );

    db.run_script(query, params)?;
    Ok(())
}

pub fn get_by_user_story(
    db: &CozoDb,
    user_story_id: &str,
) -> Result<Vec<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id], user_story_id = $us"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "us".to_string(),
        serde_json::Value::String(user_story_id.to_string()),
    );

    let result = db.run_script(query, params)?;
    let rows = result.rows;

    let business_logic: Vec<models::BusinessLogic> = rows
        .iter()
        .map(|row| {
            let user_story_id = row[2].as_str().map(String::from);
            let feature_id = row[3].as_str().map(String::from);
            models::BusinessLogic {
                id: None,
                element_qualified: row[0].as_str().unwrap_or("").to_string(),
                description: row[1].as_str().unwrap_or("").to_string(),
                user_story_id,
                feature_id,
            }
        })
        .collect();

    Ok(business_logic)
}

pub fn get_by_feature(
    db: &CozoDb,
    feature_id: &str,
) -> Result<Vec<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id], feature_id = $feat"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "feat".to_string(),
        serde_json::Value::String(feature_id.to_string()),
    );

    let result = db.run_script(query, params)?;
    let rows = result.rows;

    let business_logic: Vec<models::BusinessLogic> = rows
        .iter()
        .map(|row| {
            let user_story_id = row[2].as_str().map(String::from);
            let feature_id = row[3].as_str().map(String::from);
            models::BusinessLogic {
                id: None,
                element_qualified: row[0].as_str().unwrap_or("").to_string(),
                description: row[1].as_str().unwrap_or("").to_string(),
                user_story_id,
                feature_id,
            }
        })
        .collect();

    Ok(business_logic)
}

pub fn search_business_logic(
    db: &CozoDb,
    query_str: &str,
) -> Result<Vec<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let regex_pattern = format!(".*{}.*", query_str.to_lowercase());
    let query = format!(
        r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id], regex_matches(lowercase(description), "{}")"#,
        regex_pattern
    );

    let result = db.run_script(&query, std::collections::BTreeMap::new())?;
    let rows = result.rows;

    let business_logic: Vec<models::BusinessLogic> = rows
        .iter()
        .map(|row| {
            let user_story_id = row[2].as_str().map(String::from);
            let feature_id = row[3].as_str().map(String::from);
            models::BusinessLogic {
                id: None,
                element_qualified: row[0].as_str().unwrap_or("").to_string(),
                description: row[1].as_str().unwrap_or("").to_string(),
                user_story_id,
                feature_id,
            }
        })
        .collect();

    Ok(business_logic)
}

pub fn all_business_logic(
    db: &CozoDb,
) -> Result<Vec<models::BusinessLogic>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id]"#;

    let result = db.run_script(query, std::collections::BTreeMap::new())?;
    let rows = result.rows;

    let business_logic: Vec<models::BusinessLogic> = rows
        .iter()
        .map(|row| {
            let user_story_id = row[2].as_str().map(String::from);
            let feature_id = row[3].as_str().map(String::from);
            models::BusinessLogic {
                id: None,
                element_qualified: row[0].as_str().unwrap_or("").to_string(),
                description: row[1].as_str().unwrap_or("").to_string(),
                user_story_id,
                feature_id,
            }
        })
        .collect();

    Ok(business_logic)
}

#[allow(dead_code)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FeatureTraceEntry {
    pub element_qualified: String,
    pub description: String,
    pub user_story_id: Option<String>,
}

#[allow(dead_code)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct FeatureTraceability {
    pub feature_id: String,
    pub code_elements: Vec<FeatureTraceEntry>,
    pub count: usize,
}

#[allow(dead_code)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct UserStoryTraceEntry {
    pub element_qualified: String,
    pub description: String,
    pub feature_id: Option<String>,
}

#[allow(dead_code)]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct UserStoryTraceability {
    pub user_story_id: String,
    pub code_elements: Vec<UserStoryTraceEntry>,
    pub count: usize,
}

#[allow(dead_code)]
pub fn get_feature_traceability(
    db: &CozoDb,
    feature_id: &str,
) -> Result<FeatureTraceability, Box<dyn std::error::Error>> {
    let elements = get_by_feature(db, feature_id)?;
    let code_elements: Vec<FeatureTraceEntry> = elements
        .into_iter()
        .map(|bl| FeatureTraceEntry {
            element_qualified: bl.element_qualified,
            description: bl.description,
            user_story_id: bl.user_story_id,
        })
        .collect();
    let count = code_elements.len();
    Ok(FeatureTraceability {
        feature_id: feature_id.to_string(),
        code_elements,
        count,
    })
}

#[allow(dead_code)]
pub fn get_user_story_traceability(
    db: &CozoDb,
    user_story_id: &str,
) -> Result<UserStoryTraceability, Box<dyn std::error::Error>> {
    let elements = get_by_user_story(db, user_story_id)?;
    let code_elements: Vec<UserStoryTraceEntry> = elements
        .into_iter()
        .map(|bl| UserStoryTraceEntry {
            element_qualified: bl.element_qualified,
            description: bl.description,
            feature_id: bl.feature_id,
        })
        .collect();
    let count = code_elements.len();
    Ok(UserStoryTraceability {
        user_story_id: user_story_id.to_string(),
        code_elements,
        count,
    })
}

#[allow(dead_code)]
pub fn all_feature_traceability(
    db: &CozoDb,
) -> Result<Vec<FeatureTraceability>, Box<dyn std::error::Error>> {
    let all = all_business_logic(db)?;
    let mut feature_map: std::collections::HashMap<String, Vec<FeatureTraceEntry>> =
        std::collections::HashMap::new();

    for bl in all {
        if let Some(ref fid) = bl.feature_id {
            let entry = FeatureTraceEntry {
                element_qualified: bl.element_qualified.clone(),
                description: bl.description.clone(),
                user_story_id: bl.user_story_id.clone(),
            };
            feature_map.entry(fid.clone()).or_default().push(entry);
        }
    }

    let traces: Vec<FeatureTraceability> = feature_map
        .into_iter()
        .map(|(feature_id, code_elements)| {
            let count = code_elements.len();
            FeatureTraceability {
                feature_id,
                code_elements,
                count,
            }
        })
        .collect();
    Ok(traces)
}

#[allow(dead_code)]
pub fn all_user_story_traceability(
    db: &CozoDb,
) -> Result<Vec<UserStoryTraceability>, Box<dyn std::error::Error>> {
    let all = all_business_logic(db)?;
    let mut story_map: std::collections::HashMap<String, Vec<UserStoryTraceEntry>> =
        std::collections::HashMap::new();

    for bl in all {
        if let Some(ref sid) = bl.user_story_id {
            let entry = UserStoryTraceEntry {
                element_qualified: bl.element_qualified.clone(),
                description: bl.description.clone(),
                feature_id: bl.feature_id.clone(),
            };
            story_map.entry(sid.clone()).or_default().push(entry);
        }
    }

    let traces: Vec<UserStoryTraceability> = story_map
        .into_iter()
        .map(|(user_story_id, code_elements)| {
            let count = code_elements.len();
            UserStoryTraceability {
                user_story_id,
                code_elements,
                count,
            }
        })
        .collect();
    Ok(traces)
}

#[allow(dead_code)]
pub fn find_by_business_domain(
    db: &CozoDb,
    domain: &str,
) -> Result<Vec<models::BusinessLogic>, Box<dyn std::error::Error>> {
    search_business_logic(db, domain)
}

#[allow(dead_code)]
pub fn get_documented_by(
    db: &CozoDb,
    element_qualified: &str,
) -> Result<Vec<models::DocLink>, Box<dyn std::error::Error>> {
    let query = r#"?[target_qualified, rel_type, metadata, confidence] := *relationships[source_qualified, target_qualified, rel_type, metadata, confidence], source_qualified = $sq, rel_type = "documented_by""#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "sq".to_string(),
        serde_json::Value::String(element_qualified.to_string()),
    );

    let result = db.run_script(query, params)?;
    let rows = result.rows;

    let doc_links: Vec<models::DocLink> = rows
        .iter()
        .filter_map(|row| {
            let _source = row[0].as_str().unwrap_or("");
            let doc_qualified = row[1].as_str().unwrap_or("").to_string();
            let _rel_type = row[2].as_str().unwrap_or("");
            let _confidence = row[3].as_f64().unwrap_or(1.0);
            let metadata_str = row.get(4).and_then(|v| v.as_str()).unwrap_or("{}");
            let metadata: serde_json::Value = serde_json::from_str(metadata_str).ok()?;

            let doc_title = metadata
                .get("title")
                .and_then(|v| v.as_str())
                .unwrap_or("Untitled")
                .to_string();
            let context = metadata
                .get("context")
                .and_then(|v| v.as_str())
                .map(String::from);

            Some(models::DocLink {
                doc_qualified,
                doc_title,
                context,
            })
        })
        .collect();

    Ok(doc_links)
}

#[allow(dead_code)]
pub fn get_traceability_report(
    db: &CozoDb,
    element_qualified: &str,
) -> Result<models::TraceabilityReport, Box<dyn std::error::Error>> {
    let bl = get_business_logic(db, element_qualified)?;
    let doc_links = get_documented_by(db, element_qualified)?;

    let entry = models::TraceabilityEntry {
        element_qualified: element_qualified.to_string(),
        description: bl
            .as_ref()
            .map(|b| b.description.clone())
            .unwrap_or_default(),
        user_story_id: bl.as_ref().and_then(|b| b.user_story_id.clone()),
        feature_id: bl.as_ref().and_then(|b| b.feature_id.clone()),
        doc_links,
    };

    Ok(models::TraceabilityReport {
        element_qualified: element_qualified.to_string(),
        entries: vec![entry],
        count: 1,
    })
}

#[allow(dead_code)]
pub fn get_code_for_requirement(
    db: &CozoDb,
    requirement_id: &str,
) -> Result<Vec<models::TraceabilityEntry>, Box<dyn std::error::Error>> {
    let query = r#"?[element_qualified, description, user_story_id, feature_id] := *business_logic[element_qualified, description, user_story_id, feature_id], user_story_id = $us"#;
    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "us".to_string(),
        serde_json::Value::String(requirement_id.to_string()),
    );

    let result = db.run_script(query, params)?;
    let rows = result.rows;

    let mut entries = Vec::new();
    for row in rows {
        let element_qualified = row[0].as_str().unwrap_or("").to_string();
        let description = row[1].as_str().unwrap_or("").to_string();
        let user_story_id = row[2].as_str().map(String::from);
        let feature_id = row[3].as_str().map(String::from);

        let doc_links = get_documented_by(db, &element_qualified)?;

        entries.push(models::TraceabilityEntry {
            element_qualified,
            description,
            user_story_id,
            feature_id,
            doc_links,
        });
    }

    Ok(entries)
}

pub fn record_metric(
    db: &CozoDb,
    metric: &models::ContextMetric,
) -> Result<(), Box<dyn std::error::Error>> {
    let query = r#"?[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted] <- [[ $tool, $ts, $path, $in_tok, $out_tok, $out_elem, $exec_ms, $base_tok, $base_lines, $saved, $sav_pct, $correct, $total, $f1, $qpat, $qfile, $qdepth, $success, false ]] :put context_metrics { tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted }"#;

    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "tool".to_string(),
        serde_json::Value::String(metric.tool_name.clone()),
    );
    params.insert(
        "ts".to_string(),
        serde_json::Value::Number(metric.timestamp.into()),
    );
    params.insert(
        "path".to_string(),
        serde_json::Value::String(metric.project_path.clone()),
    );
    params.insert(
        "in_tok".to_string(),
        serde_json::Value::Number(metric.input_tokens.into()),
    );
    params.insert(
        "out_tok".to_string(),
        serde_json::Value::Number(metric.output_tokens.into()),
    );
    params.insert(
        "out_elem".to_string(),
        serde_json::Value::Number(metric.output_elements.into()),
    );
    params.insert(
        "exec_ms".to_string(),
        serde_json::Value::Number(metric.execution_time_ms.into()),
    );
    params.insert(
        "base_tok".to_string(),
        serde_json::Value::Number(metric.baseline_tokens.into()),
    );
    params.insert(
        "base_lines".to_string(),
        serde_json::Value::Number(metric.baseline_lines_scanned.into()),
    );
    params.insert(
        "saved".to_string(),
        serde_json::Value::Number(metric.tokens_saved.into()),
    );
    params.insert(
        "sav_pct".to_string(),
        serde_json::Value::Number(
            serde_json::Number::from_f64(metric.savings_percent)
                .unwrap_or(serde_json::Number::from(0)),
        ),
    );
    params.insert(
        "correct".to_string(),
        metric
            .correct_elements
            .map(|v| serde_json::Value::Number(v.into()))
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "total".to_string(),
        metric
            .total_expected
            .map(|v| serde_json::Value::Number(v.into()))
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "f1".to_string(),
        metric
            .f1_score
            .map(|v| {
                serde_json::Value::Number(
                    serde_json::Number::from_f64(v).unwrap_or(serde_json::Number::from(0)),
                )
            })
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "qpat".to_string(),
        metric
            .query_pattern
            .clone()
            .map(serde_json::Value::String)
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "qfile".to_string(),
        metric
            .query_file
            .clone()
            .map(serde_json::Value::String)
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "qdepth".to_string(),
        metric
            .query_depth
            .map(|v| serde_json::Value::Number(v.into()))
            .unwrap_or(serde_json::Value::Null),
    );
    params.insert(
        "success".to_string(),
        serde_json::Value::Bool(metric.success),
    );

    db.run_script(query, params)?;
    Ok(())
}

pub fn get_metrics_summary(
    db: &CozoDb,
    tool_filter: Option<&str>,
    retention_days: i32,
) -> Result<models::MetricsSummary, Box<dyn std::error::Error>> {
    let cutoff_timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs() as i64
        - (retention_days as i64 * 24 * 60 * 60);

    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "cutoff".to_string(),
        serde_json::Value::Number(cutoff_timestamp.into()),
    );

    let query = if let Some(ref tool) = tool_filter {
        params.insert(
            "tool".to_string(),
            serde_json::Value::String(tool.to_string()),
        );
        r#"?[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted] := *context_metrics[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted], timestamp >= $cutoff, tool_name = $tool, is_deleted = false"#
    } else {
        r#"?[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted] := *context_metrics[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted], timestamp >= $cutoff, is_deleted = false"#
    };

    let result = db.run_script(query, params.clone())?;

    let mut summary = models::MetricsSummary {
        total_invocations: 0,
        total_tokens_saved: 0,
        average_savings_percent: 0.0,
        average_correctness_percent: 0.0,
        retention_days,
        by_tool: Vec::new(),
        by_day: Vec::new(),
    };

    let mut sum_savings_percent = 0.0;
    let mut count_positive_savings = 0i64;
    let mut sum_correctness_percent = 0.0;
    let mut count_has_correctness = 0i64;
    let mut by_tool_map: std::collections::HashMap<String, (i64, i64, f64, f64, i64)> =
        std::collections::HashMap::new();

    for row in &result.rows {
        summary.total_invocations += 1;
        let saved = row[9].as_i64().unwrap_or(0);
        let pct = row[10].as_f64().unwrap_or(0.0);
        let correct = row[12].as_i64().unwrap_or(0);
        let total = row[13].as_i64().unwrap_or(0);

        // Only add positive savings to the total
        if saved > 0 {
            summary.total_tokens_saved += saved;
            sum_savings_percent += pct;
            count_positive_savings += 1;
        }

        // Calculate correctness percentage if both correct and total exist
        if total > 0 {
            let correctness = (correct as f64 / total as f64) * 100.0;
            sum_correctness_percent += correctness;
            count_has_correctness += 1;
        }

        let tool_name = row[0].as_str().unwrap_or("unknown").to_string();
        let entry = by_tool_map
            .entry(tool_name.clone())
            .or_insert((0, 0, 0.0, 0.0, 0));
        entry.0 += 1; // calls
        if saved > 0 {
            entry.1 += saved; // total_saved
        }
        entry.2 += pct; // sum_pct
        if total > 0 {
            entry.3 += (correct as f64 / total as f64) * 100.0; // sum_correctness
            entry.4 += 1; // count_has_correctness
        }
    }

    if count_positive_savings > 0 {
        summary.average_savings_percent = sum_savings_percent / count_positive_savings as f64;
    }
    if count_has_correctness > 0 {
        summary.average_correctness_percent =
            sum_correctness_percent / count_has_correctness as f64;
    }

    for (tool_name, (calls, total_saved, sum_pct, sum_correct, count_correct)) in by_tool_map {
        summary.by_tool.push(models::ToolMetrics {
            tool_name,
            calls,
            total_saved,
            avg_savings_percent: if calls > 0 {
                sum_pct / calls as f64
            } else {
                0.0
            },
            avg_correctness_percent: if count_correct > 0 {
                sum_correct / count_correct as f64
            } else {
                0.0
            },
        });
    }

    Ok(summary)
}

pub fn cleanup_old_metrics(
    db: &CozoDb,
    retention_days: i32,
) -> Result<i64, Box<dyn std::error::Error>> {
    let cutoff_timestamp = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .unwrap()
        .as_secs() as i64
        - (retention_days as i64 * 24 * 60 * 60);

    let count_query = r#"?[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted] := *context_metrics[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted], timestamp < $cutoff"#;

    let mut params = std::collections::BTreeMap::new();
    params.insert(
        "cutoff".to_string(),
        serde_json::Value::Number(cutoff_timestamp.into()),
    );

    let count_result = db.run_script(count_query, params)?;
    let deleted_count = count_result.rows.len() as i64;

    if deleted_count > 0 {
        let mut delete_params = std::collections::BTreeMap::new();
        delete_params.insert(
            "cutoff".to_string(),
            serde_json::Value::Number(cutoff_timestamp.into()),
        );
        let delete_query = r#":delete context_metrics where timestamp < $cutoff"#;
        if let Err(e) = db.run_script(delete_query, delete_params) {
            eprintln!("Warning: cleanup delete failed: {}", e);
        }
    }

    Ok(deleted_count)
}

pub fn reset_metrics(db: &CozoDb) -> Result<i64, Box<dyn std::error::Error>> {
    let count_query = r#"?[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted] := *context_metrics[tool_name, timestamp, project_path, input_tokens, output_tokens, output_elements, execution_time_ms, baseline_tokens, baseline_lines_scanned, tokens_saved, savings_percent, correct_elements, total_expected, f1_score, query_pattern, query_file, query_depth, success, is_deleted]"#;

    let count_result = db.run_script(count_query, Default::default())?;
    let deleted_count = count_result.rows.len() as i64;
    if deleted_count > 0 {
        let delete_query =
            r#":delete context_metrics where tool_name != "NON_EXISTENT_TOOL_NAME_123456789""#;
        if let Err(e) = db.run_script(delete_query, Default::default()) {
            eprintln!("Warning: reset delete failed: {}", e);
        }
    }
    Ok(deleted_count)
}
