//! Checklist management

use crate::error::Result;
use crate::phase::ProjectPhase;
use crate::LifecycleError;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use syntaxis_bridge::task_actions::TaskAction;

/// Task priority level
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum TaskPriority {
    /// Low priority
    Low,
    /// Medium priority
    #[default]
    Medium,
    /// High priority
    High,
}

impl std::fmt::Display for TaskPriority {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Low => write!(f, "Low"),
            Self::Medium => write!(f, "Medium"),
            Self::High => write!(f, "High"),
        }
    }
}

/// Task type/category
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum TaskType {
    /// Architecture/design task
    #[serde(rename = "arch")]
    Architecture,
    /// Feature implementation
    #[serde(rename = "feature")]
    #[default]
    Feature,
    /// Testing task
    #[serde(rename = "test")]
    Test,
    /// Debugging/troubleshooting
    #[serde(rename = "debug")]
    Debug,
    /// Code review
    #[serde(rename = "review")]
    Review,
    /// Documentation
    #[serde(rename = "docs")]
    Documentation,
    /// Refactoring
    #[serde(rename = "refactor")]
    Refactor,
    /// Bug fix
    #[serde(rename = "bugfix")]
    BugFix,
    /// Custom task type
    #[serde(rename = "custom")]
    Custom(String),
}

impl std::fmt::Display for TaskType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Architecture => write!(f, "Architecture"),
            Self::Feature => write!(f, "Feature"),
            Self::Test => write!(f, "Test"),
            Self::Debug => write!(f, "Debug"),
            Self::Review => write!(f, "Review"),
            Self::Documentation => write!(f, "Documentation"),
            Self::Refactor => write!(f, "Refactor"),
            Self::BugFix => write!(f, "Bug Fix"),
            Self::Custom(t) => write!(f, "{}", t),
        }
    }
}

impl TaskType {
    /// Get all predefined task types (excluding Custom)
    pub fn predefined_types() -> Vec<Self> {
        vec![
            Self::Architecture,
            Self::Feature,
            Self::Test,
            Self::Debug,
            Self::Review,
            Self::Documentation,
            Self::Refactor,
            Self::BugFix,
        ]
    }

    /// Get short identifier for task type
    pub fn short_id(&self) -> &str {
        match self {
            Self::Architecture => "arch",
            Self::Feature => "feature",
            Self::Test => "test",
            Self::Debug => "debug",
            Self::Review => "review",
            Self::Documentation => "docs",
            Self::Refactor => "refactor",
            Self::BugFix => "bugfix",
            Self::Custom(s) => s,
        }
    }

    /// Format all available task types for display
    pub fn format_available_types() -> String {
        let types = Self::predefined_types();
        let formatted: Vec<String> = types
            .iter()
            .map(|t| format!("  • {} ({})", t, t.short_id()))
            .collect();
        formatted.join("\n")
    }

    /// Parse task type from string (short_id or Display name)
    #[allow(clippy::should_implement_trait)]
    pub fn from_str(s: &str) -> Option<Self> {
        match s.to_lowercase().as_str() {
            "arch" | "architecture" => Some(Self::Architecture),
            "feature" => Some(Self::Feature),
            "test" => Some(Self::Test),
            "debug" => Some(Self::Debug),
            "review" => Some(Self::Review),
            "docs" | "documentation" => Some(Self::Documentation),
            "refactor" => Some(Self::Refactor),
            "bugfix" | "bug" => Some(Self::BugFix),
            custom => Some(Self::Custom(custom.to_string())),
        }
    }
}

/// Task state
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
#[derive(Default)]
pub enum TaskState {
    /// Task is planned
    #[serde(rename = "planned")]
    #[default]
    Planned,
    /// Task is in progress
    #[serde(rename = "in_progress")]
    InProgress,
    /// Task is blocked
    #[serde(rename = "blocked")]
    Blocked,
    /// Task is done
    #[serde(rename = "done")]
    Done,
}

impl std::fmt::Display for TaskState {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Planned => write!(f, "Planned"),
            Self::InProgress => write!(f, "In Progress"),
            Self::Blocked => write!(f, "Blocked"),
            Self::Done => write!(f, "Done"),
        }
    }
}

/// Checklist item with task tracking capabilities
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChecklistItem {
    /// Item ID
    pub id: String,
    /// Item description
    pub description: String,
    /// Task name (more specific than description)
    #[serde(default)]
    pub task_name: Option<String>,
    /// Task type (feature, test, bug fix, etc.)
    #[serde(default)]
    pub task_type: TaskType,
    /// Task priority
    #[serde(default)]
    pub task_priority: TaskPriority,
    /// Due date
    #[serde(default)]
    pub task_due: Option<DateTime<Utc>>,
    /// Time estimation (e.g., "3h", "2d", "1w")
    #[serde(default)]
    pub task_estimation: Option<String>,
    /// Task dependencies (list of task IDs)
    #[serde(default)]
    pub task_deps: Vec<String>,
    /// Task state
    #[serde(default)]
    pub task_state: TaskState,
    /// Additional notes for the task
    #[serde(default)]
    pub task_note: Option<String>,
    /// Actions to execute based on task lifecycle events
    #[serde(default)]
    pub task_actions: Vec<TaskAction>,
    /// Whether item is completed
    pub completed: bool,
    /// Whether item is required
    pub required: bool,
    /// Item category
    pub category: String,
    /// Optional notes
    pub notes: Option<String>,
    /// Completion timestamp
    pub completed_at: Option<DateTime<Utc>>,
}

impl ChecklistItem {
    /// Create a new checklist item
    pub fn new(id: impl Into<String>, description: impl Into<String>) -> Self {
        Self {
            id: id.into(),
            description: description.into(),
            task_name: None,
            task_type: TaskType::default(),
            task_priority: TaskPriority::default(),
            task_due: None,
            task_estimation: None,
            task_deps: Vec::new(),
            task_state: TaskState::default(),
            task_note: None,
            task_actions: Vec::new(),
            completed: false,
            required: true,
            category: "General".to_string(),
            notes: None,
            completed_at: None,
        }
    }

    /// Mark item as completed
    pub fn mark_completed(&mut self) {
        self.completed = true;
        self.task_state = TaskState::Done;
        self.completed_at = Some(Utc::now());
    }

    /// Mark item as incomplete
    pub fn mark_incomplete(&mut self) {
        self.completed = false;
        self.task_state = TaskState::Planned;
        self.completed_at = None;
    }

    /// Set category
    pub fn with_category(mut self, category: impl Into<String>) -> Self {
        self.category = category.into();
        self
    }

    /// Set required flag
    pub fn with_required(mut self, required: bool) -> Self {
        self.required = required;
        self
    }

    /// Add notes
    pub fn with_notes(mut self, notes: impl Into<String>) -> Self {
        self.notes = Some(notes.into());
        self
    }

    /// Set task name
    pub fn with_task_name(mut self, name: impl Into<String>) -> Self {
        self.task_name = Some(name.into());
        self
    }

    /// Set task type
    pub fn with_task_type(mut self, task_type: TaskType) -> Self {
        self.task_type = task_type;
        self
    }

    /// Set task priority
    pub fn with_priority(mut self, priority: TaskPriority) -> Self {
        self.task_priority = priority;
        self
    }

    /// Set task due date
    pub fn with_due_date(mut self, due: DateTime<Utc>) -> Self {
        self.task_due = Some(due);
        self
    }

    /// Set time estimation
    pub fn with_estimation(mut self, estimation: impl Into<String>) -> Self {
        self.task_estimation = Some(estimation.into());
        self
    }

    /// Add a dependency
    pub fn add_dependency(mut self, task_id: impl Into<String>) -> Self {
        self.task_deps.push(task_id.into());
        self
    }

    /// Set task state
    pub fn with_state(mut self, state: TaskState) -> Self {
        self.task_state = state;
        self
    }

    /// Start working on this task
    pub fn start_work(&mut self) {
        self.task_state = TaskState::InProgress;
    }

    /// Block this task
    pub fn block(&mut self) {
        self.task_state = TaskState::Blocked;
    }

    /// Unblock this task
    pub fn unblock(&mut self) {
        self.task_state = TaskState::InProgress;
    }

    /// Add an action to this task
    pub fn add_action(mut self, action: TaskAction) -> Self {
        self.task_actions.push(action);
        self
    }

    /// Get all actions for this task
    pub fn actions(&self) -> &[TaskAction] {
        &self.task_actions
    }

    /// Get mutable actions for this task
    pub fn actions_mut(&mut self) -> &mut Vec<TaskAction> {
        &mut self.task_actions
    }

    /// Remove action by ID
    pub fn remove_action(&mut self, action_id: &str) -> Option<TaskAction> {
        if let Some(pos) = self.task_actions.iter().position(|a| a.id == action_id) {
            Some(self.task_actions.remove(pos))
        } else {
            None
        }
    }

    /// Check if task has any actions
    pub fn has_actions(&self) -> bool {
        !self.task_actions.is_empty()
    }
}

/// Checklist
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Checklist {
    /// Phase
    pub phase: ProjectPhase,
    /// Checklist items
    pub items: Vec<ChecklistItem>,
}

impl Checklist {
    /// Create a new checklist
    pub fn new(phase: ProjectPhase) -> Self {
        Self {
            phase,
            items: vec![],
        }
    }

    /// Add item to checklist
    pub fn add_item(&mut self, item: ChecklistItem) {
        self.items.push(item);
    }

    /// Get item by ID
    pub fn get_item(&self, id: &str) -> Option<&ChecklistItem> {
        self.items.iter().find(|item| item.id == id)
    }

    /// Get mutable item by ID
    pub fn get_item_mut(&mut self, id: &str) -> Option<&mut ChecklistItem> {
        self.items.iter_mut().find(|item| item.id == id)
    }

    /// Get items filtered by task type
    pub fn get_items_by_type(&self, task_type: &TaskType) -> Vec<&ChecklistItem> {
        self.items
            .iter()
            .filter(|item| &item.task_type == task_type)
            .collect()
    }

    /// Get all items of specific task type (mutable)
    pub fn get_items_by_type_mut(&mut self, task_type: &TaskType) -> Vec<&mut ChecklistItem> {
        self.items
            .iter_mut()
            .filter(|item| &item.task_type == task_type)
            .collect()
    }

    /// Get items by state
    pub fn get_items_by_state(&self, state: TaskState) -> Vec<&ChecklistItem> {
        self.items
            .iter()
            .filter(|item| item.task_state == state)
            .collect()
    }

    /// Get items filtered by both type and state
    pub fn get_items_by_type_and_state(
        &self,
        task_type: &TaskType,
        state: TaskState,
    ) -> Vec<&ChecklistItem> {
        self.items
            .iter()
            .filter(|item| &item.task_type == task_type && item.task_state == state)
            .collect()
    }

    /// Mark item as completed
    pub fn mark_item_complete(&mut self, id: &str) -> Result<()> {
        if let Some(item) = self.get_item_mut(id) {
            item.mark_completed();
            Ok(())
        } else {
            Err(LifecycleError::checklist(format!("Item not found: {}", id)))
        }
    }

    /// Get completion percentage
    pub fn completion_percentage(&self) -> f32 {
        if self.items.is_empty() {
            return 0.0;
        }

        let completed = self.items.iter().filter(|item| item.completed).count();
        (completed as f32 / self.items.len() as f32) * 100.0
    }

    /// Export to markdown with task details
    pub fn export_to_markdown(&self) -> String {
        let mut md = format!("# {} Phase Checklist\n\n", self.phase);
        md.push_str(&format!(
            "**Progress:** {:.0}% ({}/{})\n\n",
            self.completion_percentage(),
            self.items.iter().filter(|i| i.completed).count(),
            self.items.len()
        ));

        let mut current_category = String::new();
        for item in &self.items {
            if current_category != item.category {
                current_category = item.category.clone();
                md.push_str(&format!("\n## {}\n\n", current_category));
            }

            let checkbox = if item.completed { "[x]" } else { "[ ]" };
            let task_name = item.task_name.as_ref().unwrap_or(&item.description);
            md.push_str(&format!(
                "- {} [{}] {}\n",
                checkbox, item.task_type, task_name
            ));

            // Add status indicators
            md.push_str(&format!("  - **Status:** {}\n", item.task_state));
            if item.task_priority != TaskPriority::Medium {
                md.push_str(&format!("  - **Priority:** {}\n", item.task_priority));
            }

            // Add due date if set
            if let Some(due) = item.task_due {
                md.push_str(&format!("  - **Due:** {}\n", due.format("%Y-%m-%d")));
            }

            // Add time estimation if set
            if let Some(estimation) = &item.task_estimation {
                md.push_str(&format!("  - **Estimation:** {}\n", estimation));
            }

            // Add dependencies if present
            if !item.task_deps.is_empty() {
                md.push_str(&format!(
                    "  - **Depends on:** {}\n",
                    item.task_deps.join(", ")
                ));
            }

            // Add notes if present
            if let Some(notes) = &item.notes {
                md.push_str(&format!("  - **Notes:** {}\n", notes));
            }
        }

        md
    }
}

/// Checklist manager
#[derive(Debug, Clone)]
pub struct ChecklistManager {
    checklists: HashMap<ProjectPhase, Checklist>,
}

impl ChecklistManager {
    /// Create a new checklist manager
    pub fn new() -> Self {
        Self {
            checklists: HashMap::new(),
        }
    }

    /// Load or create checklist for phase
    pub fn load_checklist(&mut self, phase: ProjectPhase) -> Result<&Checklist> {
        self.checklists
            .entry(phase)
            .or_insert_with(|| Checklist::new(phase));
        Ok(&self.checklists[&phase])
    }

    /// Get mutable checklist
    pub fn get_checklist_mut(&mut self, phase: ProjectPhase) -> Option<&mut Checklist> {
        self.checklists.get_mut(&phase)
    }

    /// Mark item complete
    pub fn mark_item_complete(&mut self, phase: ProjectPhase, item_id: &str) -> Result<()> {
        if let Some(checklist) = self.checklists.get_mut(&phase) {
            checklist.mark_item_complete(item_id)
        } else {
            Err(LifecycleError::checklist(format!(
                "Checklist not found for phase: {}",
                phase
            )))
        }
    }

    /// Add item to checklist
    pub fn add_item(&mut self, phase: ProjectPhase, item: ChecklistItem) -> Result<()> {
        if let Some(checklist) = self.checklists.get_mut(&phase) {
            checklist.add_item(item);
            Ok(())
        } else {
            Err(LifecycleError::checklist(format!(
                "Checklist not found for phase: {}",
                phase
            )))
        }
    }

    /// Export checklist to markdown
    pub fn export_to_markdown(&self, phase: ProjectPhase) -> Result<String> {
        if let Some(checklist) = self.checklists.get(&phase) {
            Ok(checklist.export_to_markdown())
        } else {
            Err(LifecycleError::checklist(format!(
                "Checklist not found for phase: {}",
                phase
            )))
        }
    }

    /// Get items filtered by task type across all phases
    pub fn get_all_items_by_type(
        &self,
        task_type: &TaskType,
    ) -> Vec<(&ProjectPhase, &ChecklistItem)> {
        let mut results = Vec::new();
        for (phase, checklist) in &self.checklists {
            for item in checklist.get_items_by_type(task_type) {
                results.push((phase, item));
            }
        }
        results
    }

    /// Get items filtered by state across all phases
    pub fn get_all_items_by_state(&self, state: TaskState) -> Vec<(&ProjectPhase, &ChecklistItem)> {
        let mut results = Vec::new();
        for (phase, checklist) in &self.checklists {
            for item in checklist.get_items_by_state(state) {
                results.push((phase, item));
            }
        }
        results
    }

    /// Get all items across all phases (for a specific type if provided)
    pub fn get_all_items(
        &self,
        task_type: Option<&TaskType>,
    ) -> Vec<(&ProjectPhase, &ChecklistItem)> {
        match task_type {
            Some(tt) => self.get_all_items_by_type(tt),
            None => {
                let mut results = Vec::new();
                for (phase, checklist) in &self.checklists {
                    for item in &checklist.items {
                        results.push((phase, item));
                    }
                }
                results
            }
        }
    }

    /// Count items by task type across all phases
    pub fn count_by_type(&self, task_type: &TaskType) -> usize {
        self.checklists
            .values()
            .map(|checklist| checklist.get_items_by_type(task_type).len())
            .sum()
    }

    /// Count items by state across all phases
    pub fn count_by_state(&self, state: TaskState) -> usize {
        self.checklists
            .values()
            .map(|checklist| checklist.get_items_by_state(state).len())
            .sum()
    }

    /// Get summary by task type
    pub fn summary_by_type(&self) -> Vec<(TaskType, usize, usize)> {
        let mut summary = Vec::new();
        for task_type in TaskType::predefined_types() {
            let total = self.count_by_type(&task_type);
            let completed = self
                .checklists
                .values()
                .map(|checklist| {
                    checklist
                        .get_items_by_type(&task_type)
                        .iter()
                        .filter(|item| item.completed)
                        .count()
                })
                .sum();
            if total > 0 {
                summary.push((task_type, completed, total));
            }
        }
        summary
    }
}

impl Default for ChecklistManager {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_checklist_item_creation() {
        let item = ChecklistItem::new("test", "Test item");
        assert_eq!(item.id, "test");
        assert!(!item.completed);
    }

    #[test]
    fn test_checklist_completion() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);
        checklist.add_item(ChecklistItem::new("item1", "Item 1"));
        checklist.add_item(ChecklistItem::new("item2", "Item 2"));

        assert_eq!(checklist.completion_percentage(), 0.0);

        checklist.mark_item_complete("item1").unwrap();
        assert_eq!(checklist.completion_percentage(), 50.0);
    }

    #[test]
    fn test_checklist_export_markdown() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);
        checklist.add_item(ChecklistItem::new("item1", "Item 1"));

        let md = checklist.export_to_markdown();
        assert!(md.contains("devel Phase Checklist"));
        assert!(md.contains("[ ] [Feature] Item 1")); // Default task_type is Feature
    }

    #[test]
    fn test_task_priority_default() {
        assert_eq!(TaskPriority::default(), TaskPriority::Medium);
    }

    #[test]
    fn test_task_priority_ordering() {
        assert!(TaskPriority::Low < TaskPriority::Medium);
        assert!(TaskPriority::Medium < TaskPriority::High);
    }

    #[test]
    fn test_task_priority_display() {
        assert_eq!(TaskPriority::Low.to_string(), "Low");
        assert_eq!(TaskPriority::Medium.to_string(), "Medium");
        assert_eq!(TaskPriority::High.to_string(), "High");
    }

    #[test]
    fn test_task_type_default() {
        assert_eq!(TaskType::default(), TaskType::Feature);
    }

    #[test]
    fn test_task_type_display() {
        assert_eq!(TaskType::Architecture.to_string(), "Architecture");
        assert_eq!(TaskType::Feature.to_string(), "Feature");
        assert_eq!(TaskType::Test.to_string(), "Test");
        assert_eq!(TaskType::Debug.to_string(), "Debug");
        assert_eq!(TaskType::Review.to_string(), "Review");
        assert_eq!(TaskType::Documentation.to_string(), "Documentation");
        assert_eq!(TaskType::Refactor.to_string(), "Refactor");
        assert_eq!(TaskType::BugFix.to_string(), "Bug Fix");
    }

    #[test]
    fn test_task_state_default() {
        assert_eq!(TaskState::default(), TaskState::Planned);
    }

    #[test]
    fn test_task_state_display() {
        assert_eq!(TaskState::Planned.to_string(), "Planned");
        assert_eq!(TaskState::InProgress.to_string(), "In Progress");
        assert_eq!(TaskState::Blocked.to_string(), "Blocked");
        assert_eq!(TaskState::Done.to_string(), "Done");
    }

    #[test]
    fn test_checklist_item_with_task_fields() {
        let item = ChecklistItem::new("task1", "Build feature X")
            .with_task_name("Implement feature X")
            .with_task_type(TaskType::Feature)
            .with_priority(TaskPriority::High)
            .with_estimation("3d");

        assert_eq!(item.task_name, Some("Implement feature X".to_string()));
        assert_eq!(item.task_type, TaskType::Feature);
        assert_eq!(item.task_priority, TaskPriority::High);
        assert_eq!(item.task_estimation, Some("3d".to_string()));
        assert_eq!(item.task_state, TaskState::Planned);
    }

    #[test]
    fn test_checklist_item_dependencies() {
        let item = ChecklistItem::new("task2", "Write tests")
            .add_dependency("task1")
            .add_dependency("task3");

        assert_eq!(item.task_deps.len(), 2);
        assert!(item.task_deps.contains(&"task1".to_string()));
        assert!(item.task_deps.contains(&"task3".to_string()));
    }

    #[test]
    fn test_checklist_item_state_transitions() {
        let mut item = ChecklistItem::new("task1", "Do something");
        assert_eq!(item.task_state, TaskState::Planned);

        item.start_work();
        assert_eq!(item.task_state, TaskState::InProgress);

        item.block();
        assert_eq!(item.task_state, TaskState::Blocked);

        item.unblock();
        assert_eq!(item.task_state, TaskState::InProgress);

        item.mark_completed();
        assert_eq!(item.task_state, TaskState::Done);
        assert!(item.completed);
    }

    #[test]
    fn test_checklist_with_task_details_markdown() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);
        let item = ChecklistItem::new("feature-x", "Build feature X")
            .with_task_name("Implement Feature X")
            .with_task_type(TaskType::Feature)
            .with_priority(TaskPriority::High)
            .with_estimation("5d")
            .add_dependency("design-phase")
            .with_notes("Requires API integration");

        checklist.add_item(item);

        let md = checklist.export_to_markdown();
        assert!(md.contains("Implement Feature X"));
        assert!(md.contains("[Feature]"));
        assert!(md.contains("**Status:**"));
        assert!(md.contains("**Priority:** High"));
        assert!(md.contains("**Estimation:** 5d"));
        assert!(md.contains("**Depends on:** design-phase"));
        assert!(md.contains("**Notes:** Requires API integration"));
    }

    #[test]
    fn test_task_type_predefined_types() {
        let types = TaskType::predefined_types();
        assert_eq!(types.len(), 8);
        assert!(types.contains(&TaskType::Feature));
        assert!(types.contains(&TaskType::Test));
        assert!(types.contains(&TaskType::BugFix));
    }

    #[test]
    fn test_task_type_short_id() {
        assert_eq!(TaskType::Architecture.short_id(), "arch");
        assert_eq!(TaskType::Feature.short_id(), "feature");
        assert_eq!(TaskType::Test.short_id(), "test");
        assert_eq!(TaskType::Review.short_id(), "review");
        assert_eq!(TaskType::BugFix.short_id(), "bugfix");
    }

    #[test]
    fn test_task_type_format_available() {
        let formatted = TaskType::format_available_types();
        assert!(formatted.contains("Architecture (arch)"));
        assert!(formatted.contains("Feature (feature)"));
        assert!(formatted.contains("Test (test)"));
        assert!(formatted.contains("Bug Fix (bugfix)"));
    }

    #[test]
    fn test_task_type_from_str() {
        assert_eq!(TaskType::from_str("arch"), Some(TaskType::Architecture));
        assert_eq!(
            TaskType::from_str("architecture"),
            Some(TaskType::Architecture)
        );
        assert_eq!(TaskType::from_str("feature"), Some(TaskType::Feature));
        assert_eq!(TaskType::from_str("test"), Some(TaskType::Test));
        assert_eq!(TaskType::from_str("bugfix"), Some(TaskType::BugFix));
        assert_eq!(TaskType::from_str("bug"), Some(TaskType::BugFix));
        assert_eq!(TaskType::from_str("docs"), Some(TaskType::Documentation));
        assert_eq!(
            TaskType::from_str("documentation"),
            Some(TaskType::Documentation)
        );

        // Custom types always return Some
        assert_eq!(
            TaskType::from_str("custom-type"),
            Some(TaskType::Custom("custom-type".to_string()))
        );
    }

    #[test]
    fn test_checklist_filter_by_type() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);
        checklist
            .add_item(ChecklistItem::new("feat-1", "Feature 1").with_task_type(TaskType::Feature));
        checklist.add_item(ChecklistItem::new("test-1", "Test 1").with_task_type(TaskType::Test));
        checklist
            .add_item(ChecklistItem::new("feat-2", "Feature 2").with_task_type(TaskType::Feature));

        let features = checklist.get_items_by_type(&TaskType::Feature);
        assert_eq!(features.len(), 2);

        let tests = checklist.get_items_by_type(&TaskType::Test);
        assert_eq!(tests.len(), 1);

        let bugfixes = checklist.get_items_by_type(&TaskType::BugFix);
        assert_eq!(bugfixes.len(), 0);
    }

    #[test]
    fn test_checklist_filter_by_state() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);
        let mut item1 = ChecklistItem::new("task1", "Task 1");
        let mut item2 = ChecklistItem::new("task2", "Task 2");
        item1.start_work();
        item2.mark_completed();

        checklist.add_item(item1);
        checklist.add_item(item2);

        let in_progress = checklist.get_items_by_state(TaskState::InProgress);
        assert_eq!(in_progress.len(), 1);

        let done = checklist.get_items_by_state(TaskState::Done);
        assert_eq!(done.len(), 1);
    }

    #[test]
    fn test_checklist_filter_by_type_and_state() {
        let mut checklist = Checklist::new(ProjectPhase::Devel);

        let mut feat1 = ChecklistItem::new("f1", "Feature 1").with_task_type(TaskType::Feature);
        let mut feat2 = ChecklistItem::new("f2", "Feature 2").with_task_type(TaskType::Feature);
        feat1.start_work();
        feat2.mark_completed();

        checklist.add_item(feat1);
        checklist.add_item(feat2);

        let in_progress_features =
            checklist.get_items_by_type_and_state(&TaskType::Feature, TaskState::InProgress);
        assert_eq!(in_progress_features.len(), 1);
    }

    #[test]
    fn test_checklist_manager_get_all_items_by_type() {
        let mut manager = ChecklistManager::new();
        let mut checklist_devel = Checklist::new(ProjectPhase::Devel);
        let mut checklist_review = Checklist::new(ProjectPhase::Review);

        checklist_devel
            .add_item(ChecklistItem::new("f1", "Feature 1").with_task_type(TaskType::Feature));
        checklist_devel.add_item(ChecklistItem::new("t1", "Test 1").with_task_type(TaskType::Test));
        checklist_review
            .add_item(ChecklistItem::new("f2", "Feature 2").with_task_type(TaskType::Feature));

        manager
            .checklists
            .insert(ProjectPhase::Devel, checklist_devel);
        manager
            .checklists
            .insert(ProjectPhase::Review, checklist_review);

        let features = manager.get_all_items_by_type(&TaskType::Feature);
        assert_eq!(features.len(), 2);

        let tests = manager.get_all_items_by_type(&TaskType::Test);
        assert_eq!(tests.len(), 1);
    }

    #[test]
    fn test_checklist_manager_get_all_items() {
        let mut manager = ChecklistManager::new();
        let mut checklist = Checklist::new(ProjectPhase::Devel);

        checklist.add_item(ChecklistItem::new("i1", "Item 1"));
        checklist.add_item(ChecklistItem::new("i2", "Item 2"));

        manager.checklists.insert(ProjectPhase::Devel, checklist);

        let all = manager.get_all_items(None);
        assert_eq!(all.len(), 2);

        let features_only = manager.get_all_items(Some(&TaskType::Feature));
        assert_eq!(features_only.len(), 2); // Both have Feature as default type
    }

    #[test]
    fn test_checklist_manager_count_by_type() {
        let mut manager = ChecklistManager::new();
        let mut checklist = Checklist::new(ProjectPhase::Devel);

        checklist.add_item(ChecklistItem::new("f1", "Feature 1").with_task_type(TaskType::Feature));
        checklist.add_item(ChecklistItem::new("f2", "Feature 2").with_task_type(TaskType::Feature));
        checklist.add_item(ChecklistItem::new("t1", "Test 1").with_task_type(TaskType::Test));

        manager.checklists.insert(ProjectPhase::Devel, checklist);

        assert_eq!(manager.count_by_type(&TaskType::Feature), 2);
        assert_eq!(manager.count_by_type(&TaskType::Test), 1);
        assert_eq!(manager.count_by_type(&TaskType::BugFix), 0);
    }

    #[test]
    fn test_checklist_manager_summary_by_type() {
        let mut manager = ChecklistManager::new();
        let mut checklist = Checklist::new(ProjectPhase::Devel);

        let mut feat1 = ChecklistItem::new("f1", "Feature 1").with_task_type(TaskType::Feature);
        let feat2 = ChecklistItem::new("f2", "Feature 2").with_task_type(TaskType::Feature);
        feat1.mark_completed();

        checklist.add_item(feat1);
        checklist.add_item(feat2);
        checklist.add_item(ChecklistItem::new("t1", "Test 1").with_task_type(TaskType::Test));

        manager.checklists.insert(ProjectPhase::Devel, checklist);

        let summary = manager.summary_by_type();
        assert_eq!(summary.len(), 2); // Feature and Test

        // Find Feature summary
        let feat_summary = summary
            .iter()
            .find(|(t, _, _)| matches!(t, TaskType::Feature));
        assert!(feat_summary.is_some());
        let (_, completed, total) = feat_summary.unwrap();
        assert_eq!(*completed, 1);
        assert_eq!(*total, 2);
    }

    #[test]
    fn test_checklist_item_with_task_actions() {
        use syntaxis_bridge::task_actions::{ActionType, ActionTrigger};

        let action = TaskAction::new(
            "action1".to_string(),
            ActionType::Gitops,
            ActionTrigger::OnComplete,
            serde_json::json!({}),
        );

        let item = ChecklistItem::new("task1", "Deploy feature")
            .with_task_type(TaskType::Feature)
            .add_action(action);

        assert!(item.has_actions());
        assert_eq!(item.actions().len(), 1);
        assert_eq!(item.actions()[0].action_type, ActionType::Gitops);
    }

    #[test]
    fn test_checklist_item_add_and_remove_actions() {
        use syntaxis_bridge::task_actions::{ActionType, ActionTrigger};

        let mut item = ChecklistItem::new("task1", "Test task");

        let action1 = TaskAction::new(
            "action1".to_string(),
            ActionType::Validate,
            ActionTrigger::OnCreate,
            serde_json::json!({"timeout_secs": 30}),
        );
        let action2 = TaskAction::new(
            "action2".to_string(),
            ActionType::Audit,
            ActionTrigger::OnComplete,
            serde_json::json!({}),
        );

        item = item.add_action(action1).add_action(action2);

        assert_eq!(item.actions().len(), 2);

        let removed = item.remove_action("action1");
        assert!(removed.is_some());
        assert_eq!(item.actions().len(), 1);
        assert_eq!(item.actions()[0].id, "action2");
    }
}
