use crate::error::Result;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use uuid::Uuid;
pub type TaskId = Uuid;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Priority {
Low,
Medium,
High,
Critical,
}
impl Priority {
pub fn value(&self) -> u8 {
match self {
Priority::Low => 1,
Priority::Medium => 2,
Priority::High => 3,
Priority::Critical => 4,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum TaskStatus {
Pending,
InProgress,
Completed,
Failed(String),
Cancelled,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Task {
pub id: TaskId,
pub title: String,
pub description: String,
pub required_capabilities: Vec<String>,
pub preferred_capabilities: Vec<String>,
pub priority: Priority,
pub status: TaskStatus,
pub created_at: DateTime<Utc>,
pub deadline: Option<DateTime<Utc>>,
pub estimated_effort: Option<f64>,
pub max_agents: Option<usize>,
pub min_agents: usize,
pub metadata: HashMap<String, serde_json::Value>,
}
impl Task {
pub fn new<S: Into<String>>(title: S) -> Self {
Self {
id: Uuid::new_v4(),
title: title.into(),
description: String::new(),
required_capabilities: Vec::new(),
preferred_capabilities: Vec::new(),
priority: Priority::Medium,
status: TaskStatus::Pending,
created_at: Utc::now(),
deadline: None,
estimated_effort: None,
max_agents: None,
min_agents: 1,
metadata: HashMap::new(),
}
}
pub fn description<S: Into<String>>(mut self, description: S) -> Self {
self.description = description.into();
self
}
pub fn require_capabilities(mut self, capabilities: Vec<String>) -> Self {
self.required_capabilities = capabilities;
self
}
pub fn prefer_capabilities(mut self, capabilities: Vec<String>) -> Self {
self.preferred_capabilities = capabilities;
self
}
pub fn priority(mut self, priority: Priority) -> Self {
self.priority = priority;
self
}
pub fn deadline(mut self, deadline: DateTime<Utc>) -> Self {
self.deadline = Some(deadline);
self
}
pub fn estimated_effort(mut self, effort: f64) -> Self {
self.estimated_effort = Some(effort);
self
}
pub fn agent_constraints(mut self, min: usize, max: Option<usize>) -> Self {
self.min_agents = min;
self.max_agents = max;
self
}
pub fn metadata<K, V>(mut self, key: K, value: V) -> Result<Self>
where
K: Into<String>,
V: Serialize,
{
let json_value = serde_json::to_value(value)?;
self.metadata.insert(key.into(), json_value);
Ok(self)
}
pub fn update_status(&mut self, status: TaskStatus) {
self.status = status;
}
pub fn is_active(&self) -> bool {
matches!(self.status, TaskStatus::Pending | TaskStatus::InProgress)
}
pub fn is_overdue(&self) -> bool {
if let Some(deadline) = self.deadline {
Utc::now() > deadline && self.is_active()
} else {
false
}
}
pub fn priority_score(&self) -> u8 {
let mut score = self.priority.value() * 10;
if self.is_overdue() {
score += 20;
}
score
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_task_creation() {
let task = Task::new("Test task")
.description("A test task")
.priority(Priority::High)
.require_capabilities(vec!["testing".to_string()]);
assert_eq!(task.title, "Test task");
assert_eq!(task.description, "A test task");
assert_eq!(task.priority, Priority::High);
assert_eq!(task.required_capabilities, vec!["testing"]);
assert!(task.is_active());
assert!(!task.is_overdue());
}
#[test]
fn test_priority_ordering() {
assert!(Priority::Critical.value() > Priority::High.value());
assert!(Priority::High.value() > Priority::Medium.value());
assert!(Priority::Medium.value() > Priority::Low.value());
}
#[test]
fn test_task_metadata() {
let task = Task::new("Test")
.metadata("custom_field", "custom_value")
.unwrap();
assert!(task.metadata.contains_key("custom_field"));
}
}