use std::path::Path;

use serde::{Deserialize, Serialize};

use crate::error::{ConfigError, Result};

#[derive(Debug, Clone, Deserialize)]
pub struct WorkflowsConfig {
    pub engine: EngineConfig,
    pub workflows: Vec<WorkflowConfig>,
}

#[derive(Debug, Clone, Deserialize)]
pub struct EngineConfig {
    pub max_parallel_tasks: usize,
    pub workflow_timeout: u64,
    pub approval_gates_enabled: bool,
}

#[derive(Debug, Clone, Deserialize)]
pub struct WorkflowConfig {
    pub name: String,
    pub trigger: String,
    pub stages: Vec<StageConfig>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StageConfig {
    pub name: String,
    pub agents: Vec<String>,
    #[serde(default)]
    pub parallel: bool,
    #[serde(default)]
    pub max_parallel: Option<usize>,
    #[serde(default)]
    pub approval_required: bool,
}

impl WorkflowsConfig {
    pub fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
        let content = std::fs::read_to_string(path).map_err(ConfigError::IoError)?;
        let config: WorkflowsConfig = toml::from_str(&content).map_err(ConfigError::Parse)?;

        config.validate()?;

        Ok(config)
    }

    fn validate(&self) -> Result<()> {
        if self.workflows.is_empty() {
            return Err(ConfigError::Invalid("No workflows defined".to_string()).into());
        }

        for workflow in &self.workflows {
            if workflow.stages.is_empty() {
                return Err(ConfigError::Invalid(format!(
                    "Workflow '{}' has no stages",
                    workflow.name
                ))
                .into());
            }

            for stage in &workflow.stages {
                if stage.agents.is_empty() {
                    return Err(ConfigError::Invalid(format!(
                        "Stage '{}' in workflow '{}' has no agents",
                        stage.name, workflow.name
                    ))
                    .into());
                }
            }
        }

        Ok(())
    }

    pub fn get_workflow(&self, name: &str) -> Option<&WorkflowConfig> {
        self.workflows.iter().find(|w| w.name == name)
    }
}

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

    #[test]
    fn test_parse_workflow_config() {
        let toml_str = r#"
[engine]
max_parallel_tasks = 10
workflow_timeout = 3600
approval_gates_enabled = true

[[workflows]]
name = "test_workflow"
trigger = "manual"

[[workflows.stages]]
name = "design"
agents = ["architect"]
parallel = false
approval_required = false

[[workflows.stages]]
name = "implementation"
agents = ["developer", "developer"]
parallel = true
max_parallel = 2
approval_required = false
        "#;

        let config: WorkflowsConfig = toml::from_str(toml_str).unwrap();

        assert_eq!(config.engine.max_parallel_tasks, 10);
        assert_eq!(config.workflows.len(), 1);
        assert_eq!(config.workflows[0].name, "test_workflow");
        assert_eq!(config.workflows[0].stages.len(), 2);
        assert_eq!(config.workflows[0].stages[0].name, "design");
        assert!(!config.workflows[0].stages[0].parallel);
        assert!(config.workflows[0].stages[1].parallel);
    }

    #[test]
    fn test_validation_no_workflows() {
        let config = WorkflowsConfig {
            engine: EngineConfig {
                max_parallel_tasks: 10,
                workflow_timeout: 3600,
                approval_gates_enabled: true,
            },
            workflows: vec![],
        };

        assert!(config.validate().is_err());
    }

    #[test]
    fn test_validation_no_stages() {
        let toml_str = r#"
[engine]
max_parallel_tasks = 10
workflow_timeout = 3600
approval_gates_enabled = true

[[workflows]]
name = "test_workflow"
trigger = "manual"
stages = []
        "#;

        let config: WorkflowsConfig = toml::from_str(toml_str).unwrap();
        assert!(config.validate().is_err());
    }

    #[test]
    fn test_get_workflow() {
        let toml_str = r#"
[engine]
max_parallel_tasks = 10
workflow_timeout = 3600
approval_gates_enabled = true

[[workflows]]
name = "workflow_a"
trigger = "manual"

[[workflows.stages]]
name = "stage1"
agents = ["agent1"]

[[workflows]]
name = "workflow_b"
trigger = "manual"

[[workflows.stages]]
name = "stage2"
agents = ["agent2"]
        "#;

        let config: WorkflowsConfig = toml::from_str(toml_str).unwrap();

        assert!(config.get_workflow("workflow_a").is_some());
        assert!(config.get_workflow("workflow_b").is_some());
        assert!(config.get_workflow("nonexistent").is_none());
    }
}
