//! Task enums and lazy evaluation structures for Command Pattern implementation.
//!
//! This module defines the declarative task types that replace direct AAML mutations.
//! Tasks are generated by Validator, Parser, and other stages, then executed by
//! dedicated executors (ValidateExecutor, ParserExecutor, Executer).

use crate::pipeline::parser::ValueNode;

/// A declarative validation task generated by the Validator.
///
/// Validation tasks represent specific checks that need to be performed on AST nodes.
/// They are generated during the validation phase and executed by `ValidateExecutor`.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValidationTask<'a> {
    /// Check if a value matches a registered type's constraints.
    ///
    /// # Fields
    /// - `key`: The configuration key being validated
    /// - `value`: The value to validate
    /// - `type_name`: Name of the type to validate against (e.g., "i32", "string", "vector2")
    /// - `line`: Source line number for diagnostics
    CheckTypeMatch {
        key: std::borrow::Cow<'a, str>,
        value: std::borrow::Cow<'a, str>,
        type_name: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Verify that a schema referenced in the configuration is defined.
    ///
    /// # Fields
    /// - `schema_name`: Name of the schema to check
    /// - `line`: Source line number
    VerifySchemaExists {
        schema_name: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Verify that a file referenced by an import directive exists.
    ///
    /// # Fields
    /// - `path`: Path to the file
    /// - `line`: Source line number
    VerifyFileExists {
        path: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Validate that an assignment complies with a registered schema.
    ///
    /// # Fields
    /// - `schema_name`: Name of the schema to validate against
    /// - `key`: Key being validated
    /// - `value`: Value being validated
    /// - `line`: Source line number
    ValidateAgainstSchema {
        schema_name: std::borrow::Cow<'a, str>,
        key: std::borrow::Cow<'a, str>,
        value: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Check that all required fields of a schema are present.
    ///
    /// # Fields
    /// - `schema_name`: Schema name
    /// - `missing_fields`: Required fields not found
    /// - `line`: Source line number
    CheckSchemaCompleteness {
        schema_name: std::borrow::Cow<'a, str>,
        missing_fields: Vec<std::borrow::Cow<'a, str>>,
        line: usize,
    },

    /// Verify no circular references in lookup chains.
    ///
    /// # Fields
    /// - `key`: Key being looked up
    /// - `line`: Source line number
    CheckNoCircularReference {
        key: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Verify that an object deriving from schemas implements all required fields.
    ///
    /// # Fields
    /// - `derive_path`: Derivation path (file.aam::Schema1::Schema2)
    /// - `current_key`: The context key doing the derivation
    /// - `line`: Source line number
    CheckDeriveCompleteness {
        derive_path: std::borrow::Cow<'a, str>,
        current_key: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Validate an inline list matches expected element types.
    ///
    /// # Fields
    /// - `key`: Configuration key
    /// - `items`: List items as strings
    /// - `element_type`: Expected type of each element
    /// - `line`: Source line number
    ValidateListElements {
        key: std::borrow::Cow<'a, str>,
        items: std::sync::Arc<[ValueNode<'a>]>,
        element_type: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Validate an inline object's keys and values.
    ///
    /// # Fields
    /// - `key`: Configuration key
    /// - `pairs`: Key-value pairs in the object
    /// - `line`: Source line number
    ValidateObjectStructure {
        key: std::borrow::Cow<'a, str>,
        pairs: std::sync::Arc<[(std::borrow::Cow<'a, str>, ValueNode<'a>)]>,
        line: usize,
    },
}

impl<'a> ValidationTask<'a> {
    /// Returns the line number associated with this task for error reporting.
    pub fn line(&self) -> usize {
        match self {
            ValidationTask::CheckTypeMatch { line, .. } => *line,
            ValidationTask::VerifySchemaExists { line, .. } => *line,
            ValidationTask::VerifyFileExists { line, .. } => *line,
            ValidationTask::ValidateAgainstSchema { line, .. } => *line,
            ValidationTask::CheckSchemaCompleteness { line, .. } => *line,
            ValidationTask::CheckDeriveCompleteness { line, .. } => *line,
            ValidationTask::CheckNoCircularReference { line, .. } => *line,
            ValidationTask::ValidateListElements { line, .. } => *line,
            ValidationTask::ValidateObjectStructure { line, .. } => *line,
        }
    }

    /// Returns a human-readable description of this task.
    pub fn description(&self) -> String {
        match self {
            ValidationTask::CheckTypeMatch { type_name, .. } => {
                format!("Check type match against '{}'", type_name)
            }
            ValidationTask::VerifySchemaExists { schema_name, .. } => {
                format!("Verify schema '{}' exists", schema_name)
            }
            ValidationTask::VerifyFileExists { path, .. } => {
                format!("Verify file '{}' exists", path)
            }
            ValidationTask::ValidateAgainstSchema { schema_name, .. } => {
                format!("Validate against schema '{}'", schema_name)
            }
            ValidationTask::CheckSchemaCompleteness { schema_name, .. } => {
                format!("Check completeness of schema '{}'", schema_name)
            }
            ValidationTask::CheckDeriveCompleteness { derive_path, .. } => {
                format!("Check derive completeness for '{}'", derive_path)
            }
            ValidationTask::CheckNoCircularReference { .. } => {
                "Check for circular references".to_string()
            }
            ValidationTask::ValidateListElements { element_type, .. } => {
                format!("Validate list elements are type '{}'", element_type)
            }
            ValidationTask::ValidateObjectStructure { .. } => {
                "Validate inline object structure".to_string()
            }
        }
    }
}

/// A declarative parsing task generated by the Parser.
///
/// Parse tasks represent operations that need to be performed on parsed modules,
/// variables, and scopes. They enable deferred processing and analysis.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseTask<'a> {
    /// Resolve a module reference in a scope.
    ///
    /// # Fields
    /// - `module_name`: Name of the module to resolve
    /// - `scope`: Current scope path
    /// - `line`: Source line number
    ResolveModuleReference {
        module_name: std::borrow::Cow<'a, str>,
        scope: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Resolve an imported file and apply its types and schemas to the context.
    ///
    /// # Fields
    /// - `derive_path`: Raw derive path (e.g. file.aam::SchemaName)
    /// - `line`: Source line number
    ResolveDeriveImport {
        derive_path: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Process variable assignments in a scope.
    ///
    /// # Fields
    /// - `variable_name`: Name of the variable
    /// - `value`: Variable value
    /// - `scope`: Scope path
    /// - `line`: Source line number
    ProcessVariable {
        variable_name: std::borrow::Cow<'a, str>,
        value: std::borrow::Cow<'a, str>,
        scope: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Manage scope lifecycle (entry/exit).
    ///
    /// # Fields
    /// - `scope`: Scope path
    /// - `is_entry`: true for scope entry, false for exit
    /// - `line`: Source line number
    ManageScope {
        scope: std::borrow::Cow<'a, str>,
        is_entry: bool,
        line: usize,
    },

    /// Execute a directive (e.g., @import, @derive).
    ///
    /// # Fields
    /// - `directive_name`: Name of the directive
    /// - `arguments`: Directive arguments
    /// - `line`: Source line number
    ExecuteDirective {
        directive_name: std::borrow::Cow<'a, str>,
        arguments: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Register a type definition from @type directive.
    ///
    /// # Fields
    /// - `type_name`: Name of the type being registered
    /// - `type_spec`: Type specification
    /// - `line`: Source line number
    RegisterType {
        type_name: std::borrow::Cow<'a, str>,
        type_spec: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Register a schema definition from @schema directive.
    ///
    /// # Fields
    /// - `schema_name`: Name of the schema
    /// - `fields`: Field definitions
    /// - `line`: Source line number
    RegisterSchema {
        schema_name: std::borrow::Cow<'a, str>,
        fields: std::borrow::Cow<'a, str>,
        line: usize,
    },
}

impl<'a> ParseTask<'a> {
    /// Returns the line number associated with this task.
    pub fn line(&self) -> usize {
        match self {
            ParseTask::ResolveModuleReference { line, .. } => *line,
            ParseTask::ResolveDeriveImport { line, .. } => *line,
            ParseTask::ProcessVariable { line, .. } => *line,
            ParseTask::ManageScope { line, .. } => *line,
            ParseTask::ExecuteDirective { line, .. } => *line,
            ParseTask::RegisterType { line, .. } => *line,
            ParseTask::RegisterSchema { line, .. } => *line,
        }
    }

    /// Returns a human-readable description.
    pub fn description(&self) -> String {
        match self {
            ParseTask::ResolveModuleReference { module_name, .. } => {
                format!("Resolve module reference '{}'", module_name)
            }
            ParseTask::ResolveDeriveImport { derive_path, .. } => {
                format!("Resolve derive import '{}'", derive_path)
            }
            ParseTask::ProcessVariable { variable_name, .. } => {
                format!("Process variable '{}'", variable_name)
            }
            ParseTask::ManageScope {
                scope, is_entry, ..
            } => {
                let action = if *is_entry { "Enter" } else { "Exit" };
                format!("{} scope '{}'", action, scope)
            }
            ParseTask::ExecuteDirective { directive_name, .. } => {
                format!("Execute directive '@{}'", directive_name)
            }
            ParseTask::RegisterType { type_name, .. } => {
                format!("Register type '{}'", type_name)
            }
            ParseTask::RegisterSchema { schema_name, .. } => {
                format!("Register schema '{}'", schema_name)
            }
        }
    }

    /// Performs checks that do not require mutable execution context.
    pub fn validate_stateless(&self) -> Result<(), TaskError> {
        if let ParseTask::ExecuteDirective {
            directive_name,
            line,
            ..
        } = self
            && !matches!(directive_name.as_ref(), "import" | "derive")
        {
            return Err(TaskError {
                line: *line,
                message: format!("Unknown directive: @{}", directive_name),
                task_description: self.description(),
                aaml_error: None,
            });
        }

        Ok(())
    }
}

/// A declarative execution task for the final execution phase.
///
/// Execution tasks represent the final operations to be performed to materialize
/// the configuration, independent of AAML struct manipulation.
#[derive(Debug, Clone)]
pub enum ExecutionTask<'a> {
    /// Set a configuration value in the output.
    ///
    /// # Fields
    /// - `key`: Configuration key
    /// - `value`: Value to set
    /// - `line`: Source line number
    SetValue {
        key: std::borrow::Cow<'a, str>,
        value: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Merge a value with an existing one (+=).
    ///
    /// # Fields
    /// - `key`: Key to merge
    /// - `value`: Value to merge in
    /// - `line`: Source line number
    MergeValue {
        key: std::borrow::Cow<'a, str>,
        value: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Apply schema validation to a subtree.
    ///
    /// # Fields
    /// - `schema_name`: Schema to apply
    /// - `root_keys`: Keys that are part of this schema
    /// - `line`: Source line number
    ApplySchema {
        schema_name: std::borrow::Cow<'a, str>,
        root_keys: Vec<std::borrow::Cow<'a, str>>,
        line: usize,
    },

    /// Execute inheritance from a parent configuration.
    ///
    /// # Fields
    /// - `parent_key`: Parent configuration key
    /// - `child_key`: Child configuration key
    /// - `line`: Source line number
    ExecuteInheritance {
        derive_path: std::borrow::Cow<'a, str>,
        child_key: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Import configuration from an external file.
    ///
    /// # Fields
    /// - `file_path`: Path to import
    /// - `merge_strategy`: How to merge ("override" or "merge")
    /// - `line`: Source line number
    ImportFile {
        file_path: std::borrow::Cow<'a, str>,
        merge_strategy: std::borrow::Cow<'a, str>,
        line: usize,
    },

    /// Resolve a reference to another key.
    ///
    /// # Fields
    /// - `source_key`: Key containing the reference
    /// - `target_key`: Key being referenced
    /// - `line`: Source line number
    ResolveReference {
        source_key: std::borrow::Cow<'a, str>,
        target_key: std::borrow::Cow<'a, str>,
        line: usize,
    },
}

impl<'a> ExecutionTask<'a> {
    /// Returns the line number associated with this task.
    pub fn line(&self) -> usize {
        match self {
            ExecutionTask::SetValue { line, .. } => *line,
            ExecutionTask::MergeValue { line, .. } => *line,
            ExecutionTask::ApplySchema { line, .. } => *line,
            ExecutionTask::ExecuteInheritance { line, .. } => *line,
            ExecutionTask::ImportFile { line, .. } => *line,
            ExecutionTask::ResolveReference { line, .. } => *line,
        }
    }

    /// Returns a human-readable description.
    pub fn description(&self) -> String {
        match self {
            ExecutionTask::SetValue { key, .. } => format!("Set value for key '{}'", key),
            ExecutionTask::MergeValue { key, .. } => format!("Merge value for key '{}'", key),
            ExecutionTask::ApplySchema { schema_name, .. } => {
                format!("Apply schema '{}'", schema_name)
            }
            ExecutionTask::ExecuteInheritance {
                derive_path,
                child_key,
                ..
            } => {
                format!("Execute inheritance: '{}' <- '{}'", child_key, derive_path)
            }
            ExecutionTask::ImportFile { file_path, .. } => {
                format!("Import file '{}'", file_path)
            }
            ExecutionTask::ResolveReference {
                source_key,
                target_key,
                ..
            } => {
                format!("Resolve reference: '{}' -> '{}'", source_key, target_key)
            }
        }
    }
}

/// Result of executing a batch of tasks, with error aggregation support for LSP.
#[derive(Debug, Clone)]
pub struct TaskExecutionResult {
    /// Whether all tasks executed successfully
    pub success: bool,

    /// Collected errors with line/context information
    pub errors: Vec<TaskError>,

    /// Execution statistics
    pub stats: ExecutionStats,
}

/// A single task execution error with full diagnostic context.
#[derive(Debug, Clone)]
pub struct TaskError {
    /// Associated task line number
    pub line: usize,

    /// Error message
    pub message: String,

    /// Task description for context
    pub task_description: String,

    /// AAML error details
    pub aaml_error: Option<String>,
}

/// Execution statistics for performance monitoring.
#[derive(Debug, Clone, Default)]
pub struct ExecutionStats {
    /// Total tasks executed
    pub total_tasks: usize,

    /// Successfully executed tasks
    pub successful_tasks: usize,

    /// Failed tasks
    pub failed_tasks: usize,

    /// Time spent in validation phase (milliseconds)
    pub validation_ms: u64,

    /// Time spent in parsing phase (milliseconds)
    pub parsing_ms: u64,

    /// Time spent in execution phase (milliseconds)
    pub execution_ms: u64,
}

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

    #[test]
    fn test_validation_task_line_numbers() {
        let task = ValidationTask::CheckTypeMatch {
            key: Cow::from("foo".to_string()),
            value: Cow::from("bar"),
            type_name: Cow::from("string".to_string()),
            line: 42,
        };
        assert_eq!(task.line(), 42);
    }

    #[test]
    fn test_parse_task_description() {
        let task = ParseTask::ExecuteDirective {
            directive_name: Cow::from("import"),
            arguments: Cow::from("base.aam"),
            line: 10,
        };
        assert_eq!(task.description(), "Execute directive '@import'");
    }

    #[test]
    fn test_execution_task_inheritance() {
        let task = ExecutionTask::ExecuteInheritance {
            derive_path: Cow::from("base.aam::Parent"),
            child_key: Cow::from("child"),
            line: 5,
        };
        assert_eq!(
            task.description(),
            "Execute inheritance: 'child' <- 'base.aam::Parent'"
        );
    }
}
