//! Built-in Skills
//!
//! Predefined skills for common operations.

use super::{Skill, SkillParams, SkillContext, SkillResult, SkillError, SkillCategory};
use async_trait::async_trait;
use serde_json;

/// Commit skill - creates a git commit with AI-generated message
pub struct CommitSkill;

#[async_trait]
impl Skill for CommitSkill {
    fn name(&self) -> &str {
        "commit"
    }

    fn description(&self) -> &str {
        "Create a git commit with an AI-generated commit message based on changes"
    }

    fn examples(&self) -> Vec<String> {
        vec![
            "/commit - Create a commit with all staged changes".to_string(),
            "/commit --message \"Fixed bug\" - Commit with custom message".to_string(),
            "/commit --amend - Amend the previous commit".to_string(),
        ]
    }

    fn parameter_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "message": {
                    "type": "string",
                    "description": "Custom commit message (optional)"
                },
                "amend": {
                    "type": "boolean",
                    "description": "Amend the previous commit"
                },
                "all": {
                    "type": "boolean",
                    "description": "Commit all changes (including unstaged)"
                }
            }
        })
    }

    async fn execute(&self, params: SkillParams, context: SkillContext) -> Result<SkillResult, SkillError> {
        // In a real implementation, this would:
        // 1. Get git status to see changes
        // 2. Generate commit message using AI if not provided
        // 3. Execute git commit
        // 4. Return result

        let custom_message = params.named_params.get("message");
        let amend = params.flags.contains_key("amend");
        let all = params.flags.contains_key("all");

        // For now, return a mock result
        Ok(SkillResult {
            success: true,
            message: format!(
                "Git commit skill executed. amend={}, all={}, custom_message={}",
                amend,
                all,
                custom_message.unwrap_or(&"<auto-generated>".to_string())
            ),
            output: Some(serde_json::json!({
                "skill": "commit",
                "parameters": {
                    "amend": amend,
                    "all": all,
                    "has_custom_message": custom_message.is_some()
                }
            })),
            metadata: std::collections::HashMap::new(),
        })
    }
}

/// Review skill - perform code review
pub struct ReviewSkill;

#[async_trait]
impl Skill for ReviewSkill {
    fn name(&self) -> &str {
        "review"
    }

    fn description(&self) -> &str {
        "Perform AI-powered code review on current changes or specified files"
    }

    fn examples(&self) -> Vec<String> {
        vec![
            "/review - Review all changed files".to_string(),
            "/review src/main.rs - Review specific file".to_string(),
            "/review --diff - Review based on diff output".to_string(),
        ]
    }

    fn parameter_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "files": {
                    "type": "array",
                    "items": {
                        "type": "string"
                    },
                    "description": "Files to review"
                },
                "diff": {
                    "type": "boolean",
                    "description": "Review based on diff output"
                },
                "strict": {
                    "type": "boolean",
                    "description": "Enable strict review mode"
                }
            }
        })
    }

    async fn execute(&self, params: SkillParams, _context: SkillContext) -> Result<SkillResult, SkillError> {
        let files: Vec<String> = params.args;
        let diff_mode = params.flags.contains_key("diff");
        let strict_mode = params.flags.contains_key("strict");

        Ok(SkillResult {
            success: true,
            message: format!(
                "Code review skill executed. files={:?}, diff={}, strict={}",
                files, diff_mode, strict_mode
            ),
            output: Some(serde_json::json!({
                "skill": "review",
                "files_reviewed": files.len(),
                "modes": {
                    "diff": diff_mode,
                    "strict": strict_mode
                }
            })),
            metadata: std::collections::HashMap::new(),
        })
    }
}

/// Test skill - run tests
pub struct TestSkill;

#[async_trait]
impl Skill for TestSkill {
    fn name(&self) -> &str {
        "test"
    }

    fn description(&self) -> &str {
        "Run tests for the current project"
    }

    fn examples(&self) -> Vec<String> {
        vec![
            "/test - Run all tests".to_string(),
            "/test --unit - Run only unit tests".to_string(),
            "/test --integration - Run only integration tests".to_string(),
        ]
    }

    fn parameter_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "unit": {
                    "type": "boolean",
                    "description": "Run unit tests only"
                },
                "integration": {
                    "type": "boolean",
                    "description": "Run integration tests only"
                },
                "watch": {
                    "type": "boolean",
                    "description": "Run in watch mode"
                },
                "coverage": {
                    "type": "boolean",
                    "description": "Generate coverage report"
                }
            }
        })
    }

    async fn execute(&self, params: SkillParams, _context: SkillContext) -> Result<SkillResult, SkillError> {
        let unit_tests = params.flags.contains_key("unit");
        let integration_tests = params.flags.contains_key("integration");
        let watch_mode = params.flags.contains_key("watch");
        let coverage = params.flags.contains_key("coverage");

        Ok(SkillResult {
            success: true,
            message: format!(
                "Test skill executed. unit={}, integration={}, watch={}, coverage={}",
                unit_tests, integration_tests, watch_mode, coverage
            ),
            output: Some(serde_json::json!({
                "skill": "test",
                "test_types": {
                    "unit": unit_tests,
                    "integration": integration_tests,
                    "all": !unit_tests && !integration_tests
                },
                "options": {
                    "watch": watch_mode,
                    "coverage": coverage
                }
            })),
            metadata: std::collections::HashMap::new(),
        })
    }
}

/// Document skill - generate documentation
pub struct DocumentSkill;

#[async_trait]
impl Skill for DocumentSkill {
    fn name(&self) -> &str {
        "document"
    }

    fn description(&self) -> &str {
        "Generate or update documentation"
    }

    fn examples(&self) -> Vec<String> {
        vec![
            "/document - Generate documentation for current project".to_string(),
            "/document --api - Generate API documentation".to_string(),
            "/document --readme - Update README.md".to_string(),
        ]
    }

    fn parameter_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "api": {
                    "type": "boolean",
                    "description": "Generate API documentation"
                },
                "readme": {
                    "type": "boolean",
                    "description": "Update README.md"
                },
                "force": {
                    "type": "boolean",
                    "description": "Force overwrite existing documentation"
                }
            }
        })
    }

    async fn execute(&self, params: SkillParams, _context: SkillContext) -> Result<SkillResult, SkillError> {
        let api_docs = params.flags.contains_key("api");
        let readme = params.flags.contains_key("readme");
        let force = params.flags.contains_key("force");

        Ok(SkillResult {
            success: true,
            message: format!(
                "Documentation skill executed. api={}, readme={}, force={}",
                api_docs, readme, force
            ),
            output: Some(serde_json::json!({
                "skill": "document",
                "documentation_types": {
                    "api": api_docs,
                    "readme": readme,
                    "all": !api_docs && !readme
                },
                "force_overwrite": force
            })),
            metadata: std::collections::HashMap::new(),
        })
    }
}

/// Build skill - build the project
pub struct BuildSkill;

#[async_trait]
impl Skill for BuildSkill {
    fn name(&self) -> &str {
        "build"
    }

    fn description(&self) -> &str {
        "Build the current project"
    }

    fn examples(&self) -> Vec<String> {
        vec![
            "/build - Build the project".to_string(),
            "/build --release - Build in release mode".to_string(),
            "/build --clean - Clean build artifacts first".to_string(),
        ]
    }

    fn parameter_schema(&self) -> serde_json::Value {
        serde_json::json!({
            "type": "object",
            "properties": {
                "release": {
                    "type": "boolean",
                    "description": "Build in release mode"
                },
                "clean": {
                    "type": "boolean",
                    "description": "Clean build artifacts first"
                },
                "verbose": {
                    "type": "boolean",
                    "description": "Enable verbose output"
                }
            }
        })
    }

    async fn execute(&self, params: SkillParams, _context: SkillContext) -> Result<SkillResult, SkillError> {
        let release_mode = params.flags.contains_key("release");
        let clean_build = params.flags.contains_key("clean");
        let verbose = params.flags.contains_key("verbose");

        Ok(SkillResult {
            success: true,
            message: format!(
                "Build skill executed. release={}, clean={}, verbose={}",
                release_mode, clean_build, verbose
            ),
            output: Some(serde_json::json!({
                "skill": "build",
                "build_mode": if release_mode { "release" } else { "debug" },
                "clean_build": clean_build,
                "verbose": verbose
            })),
            metadata: std::collections::HashMap::new(),
        })
    }
}

/// Builtin skills collection
pub struct BuiltinSkills;

impl BuiltinSkills {
    /// Get all built-in skills
    pub fn all() -> Vec<(Box<dyn Skill>, Vec<SkillCategory>)> {
        vec![
            (
                Box::new(CommitSkill) as Box<dyn Skill>,
                vec![SkillCategory::Git, SkillCategory::Utility],
            ),
            (
                Box::new(ReviewSkill),
                vec![SkillCategory::CodeReview, SkillCategory::Utility],
            ),
            (
                Box::new(TestSkill),
                vec![SkillCategory::Testing, SkillCategory::Utility],
            ),
            (
                Box::new(DocumentSkill),
                vec![SkillCategory::Documentation, SkillCategory::Utility],
            ),
            (
                Box::new(BuildSkill),
                vec![SkillCategory::ProjectSetup, SkillCategory::Utility],
            ),
        ]
    }
}