use crate::{ValidationError, ValidationResult};
use agileplus_domain::intent_graph::*;
use regex::Regex;
pub fn validate_node_completeness(graph: &IntentGraph) -> ValidationResult {
let mut errors = Vec::new();
let re = Regex::new(r"^[A-Z][a-z]+#[a-z0-9\-]+$").unwrap();
for node in &graph.nodes {
if !re.is_match(&node.id.0) {
errors.push(ValidationError::InvalidNodeId(format!(
"Node ID '{}' does not match required pattern ^[A-Z][a-z]+#[a-z0-9\\-]+$",
node.id
)));
}
if node.title.trim().is_empty() {
errors.push(ValidationError::MissingRequiredField(format!(
"Node {} is missing title",
node.id
)));
}
if node.meta.source.trim().is_empty() {
errors.push(ValidationError::MissingRequiredField(format!(
"Node {} meta.source is empty",
node.id
)));
}
if node.meta.timestamp.trim().is_empty() {
errors.push(ValidationError::MissingRequiredField(format!(
"Node {} meta.timestamp is empty",
node.id
)));
}
if let Some(c) = node.meta.confidence {
if !(0.0..=1.0).contains(&c) {
errors.push(ValidationError::MissingRequiredField(format!(
"Node {} meta.confidence {} is out of range [0.0, 1.0]",
node.id, c
)));
}
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
pub fn validate_node_ids_only(graph: &IntentGraph) -> ValidationResult {
let mut errors = Vec::new();
let re = Regex::new(r"^[A-Z][a-z]+#[a-z0-9\-]+$").unwrap();
for node in &graph.nodes {
if !re.is_match(&node.id.0) {
errors.push(ValidationError::InvalidNodeId(format!(
"Node ID '{}' does not match required pattern",
node.id
)));
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}