//! MCP prompt handlers

use anyhow::Result;
use kogral_core::{
    models::{Edge, Graph, NodeType},
    storage::{filesystem::FilesystemStorage, Storage},
};
use serde_json::Value;
use tracing::info;

use crate::types::{Prompt, PromptArgument, PromptContent, PromptMessage};

/// List available prompts
pub fn list_prompts() -> Vec<Prompt> {
    vec![
        Prompt {
            name: "kogral/summarize_project".to_string(),
            description: "Generate a comprehensive summary of the project's KOGRAL".to_string(),
            arguments: Some(vec![PromptArgument {
                name: "project".to_string(),
                description: "Project name to summarize".to_string(),
                required: false,
            }]),
        },
        Prompt {
            name: "kogral/find_related".to_string(),
            description: "Find nodes related to a given topic or node".to_string(),
            arguments: Some(vec![
                PromptArgument {
                    name: "topic".to_string(),
                    description: "Topic or node ID to find related items for".to_string(),
                    required: true,
                },
                PromptArgument {
                    name: "depth".to_string(),
                    description: "How many levels deep to traverse relationships (default: 1)"
                        .to_string(),
                    required: false,
                },
            ]),
        },
    ]
}

/// Execute a prompt
pub async fn execute_prompt(name: &str, arguments: Value) -> Result<Vec<PromptMessage>> {
    info!("Executing prompt: {} with args: {}", name, arguments);

    match name {
        "kogral/summarize_project" => prompt_summarize_project(arguments).await,
        "kogral/find_related" => prompt_find_related(arguments).await,
        _ => Err(anyhow::anyhow!("Unknown prompt: {}", name)),
    }
}

/// Generate project summary prompt
async fn prompt_summarize_project(args: Value) -> Result<Vec<PromptMessage>> {
    let project = args["project"].as_str().unwrap_or("default");

    let storage = FilesystemStorage::new(std::path::PathBuf::from(".kogral"));
    let graph = storage.load_graph(project).await?;

    let mut summary = String::from("# Project Knowledge Base Summary\n\n");

    // Overview statistics
    summary.push_str(&format!("**Project:** {}\n", graph.name));
    summary.push_str(&format!("**Total Nodes:** {}\n", graph.nodes.len()));
    summary.push_str(&format!(
        "**Total Relationships:** {}\n\n",
        graph.edges.len()
    ));

    // Count nodes by type
    let mut type_counts = std::collections::HashMap::new();
    for node in graph.nodes.values() {
        *type_counts
            .entry(format!("{:?}", node.node_type))
            .or_insert(0) += 1;
    }

    summary.push_str("## Nodes by Type\n\n");
    for (node_type, count) in &type_counts {
        summary.push_str(&format!("- **{}:** {}\n", node_type, count));
    }
    summary.push('\n');

    // Recent decisions
    let mut decisions: Vec<_> = graph
        .nodes
        .values()
        .filter(|n| n.node_type == NodeType::Decision)
        .collect();
    decisions.sort_by(|a, b| b.created.cmp(&a.created));

    if !decisions.is_empty() {
        summary.push_str("## Recent Architectural Decisions\n\n");
        for decision in decisions.iter().take(5) {
            summary.push_str(&format!("- **{}** ({})\n", decision.title, decision.id));
            if let Some(decision_text) = decision.metadata.get("decision") {
                if let Some(text) = decision_text.as_str() {
                    let preview: String = text
                        .lines()
                        .next()
                        .unwrap_or("")
                        .chars()
                        .take(100)
                        .collect();
                    summary.push_str(&format!("  {}\n", preview));
                }
            }
        }
        summary.push('\n');
    }

    // Active guidelines
    let guidelines: Vec<_> = graph
        .nodes
        .values()
        .filter(|n| n.node_type == NodeType::Guideline)
        .collect();

    if !guidelines.is_empty() {
        summary.push_str("## Active Guidelines\n\n");
        for guideline in guidelines.iter().take(10) {
            summary.push_str(&format!("- **{}**\n", guideline.title));
            if let Some(lang) = guideline.metadata.get("language").and_then(|v| v.as_str()) {
                summary.push_str(&format!("  Language: {}\n", lang));
            }
            if let Some(cat) = guideline.metadata.get("category").and_then(|v| v.as_str()) {
                summary.push_str(&format!("  Category: {}\n", cat));
            }
        }
        summary.push('\n');
    }

    // Key patterns
    let patterns: Vec<_> = graph
        .nodes
        .values()
        .filter(|n| n.node_type == NodeType::Pattern)
        .collect();

    if !patterns.is_empty() {
        summary.push_str("## Design Patterns\n\n");
        for pattern in patterns {
            summary.push_str(&format!("- **{}**\n", pattern.title));
        }
        summary.push('\n');
    }

    // Top tags
    let mut tag_counts = std::collections::HashMap::new();
    for node in graph.nodes.values() {
        for tag in &node.tags {
            *tag_counts.entry(tag.clone()).or_insert(0) += 1;
        }
    }

    if !tag_counts.is_empty() {
        summary.push_str("## Most Common Tags\n\n");
        let mut tags: Vec<_> = tag_counts.iter().collect();
        tags.sort_by(|a, b| b.1.cmp(a.1));
        for (tag, count) in tags.iter().take(10) {
            summary.push_str(&format!("- **{}**: {} nodes\n", tag, count));
        }
    }

    Ok(vec![PromptMessage {
        role: "user".to_string(),
        content: PromptContent::Text { text: summary },
    }])
}

/// Helper to format related edges into text
fn format_edge_relationships(edges: &[&Edge], graph: &Graph, node_id: &str, output: &mut String) {
    for edge in edges {
        if edge.from == node_id {
            if let Some(target) = graph.get_node(&edge.to) {
                output.push_str(&format!(
                    "- **{:?}** → [{}]({})\n",
                    edge.edge_type, target.title, target.id
                ));
            }
        } else if let Some(source) = graph.get_node(&edge.from) {
            output.push_str(&format!(
                "- [{}]({}) → **{:?}**\n",
                source.title, source.id, edge.edge_type
            ));
        }
    }
}

/// Find related nodes prompt
async fn prompt_find_related(args: Value) -> Result<Vec<PromptMessage>> {
    let topic = args["topic"]
        .as_str()
        .ok_or_else(|| anyhow::anyhow!("Missing topic argument"))?;
    let depth = args["depth"].as_u64().unwrap_or(1) as usize;

    let storage = FilesystemStorage::new(std::path::PathBuf::from(".kogral"));
    let graph = storage.load_graph("default").await?;

    let mut related_text = format!("# Related Nodes for '{}'\n\n", topic);

    // Find the target node
    let target_node = graph
        .nodes
        .values()
        .find(|n| n.id == topic || n.title.to_lowercase().contains(&topic.to_lowercase()));

    if let Some(node) = target_node {
        related_text.push_str(&format!("## Target Node: {}\n\n", node.title));
        related_text.push_str(&format!("**ID:** {}\n", node.id));
        related_text.push_str(&format!("**Type:** {:?}\n\n", node.node_type));

        // Find direct relationships
        related_text.push_str("## Direct Relationships\n\n");
        let related_edges: Vec<_> = graph
            .edges
            .iter()
            .filter(|e| e.from == node.id || e.to == node.id)
            .collect();

        if related_edges.is_empty() {
            related_text.push_str("No direct relationships found.\n\n");
        } else {
            format_edge_relationships(&related_edges, &graph, &node.id, &mut related_text);
            related_text.push('\n');
        }

        // If depth > 1, traverse further
        if depth > 1 {
            related_text.push_str("## Extended Relationships\n\n");
            related_text.push_str(&format!(
                "(Traversing {} level(s) deep - feature coming soon)\n\n",
                depth
            ));
        }

        // Find nodes with similar tags
        if !node.tags.is_empty() {
            related_text.push_str("## Nodes with Similar Tags\n\n");
            let similar: Vec<_> = graph
                .nodes
                .values()
                .filter(|n| n.id != node.id && n.tags.iter().any(|tag| node.tags.contains(tag)))
                .take(5)
                .collect();

            for similar_node in similar {
                let common_tags: Vec<String> = similar_node
                    .tags
                    .iter()
                    .filter(|tag| node.tags.contains(tag))
                    .cloned()
                    .collect();
                related_text.push_str(&format!(
                    "- **{}** (common tags: {})\n",
                    similar_node.title,
                    common_tags.join(", ")
                ));
            }
        }
    } else {
        // Topic search mode
        related_text.push_str("## Search Results\n\n");
        let results: Vec<_> = graph
            .nodes
            .values()
            .filter(|n| {
                n.title.to_lowercase().contains(&topic.to_lowercase())
                    || n.content.to_lowercase().contains(&topic.to_lowercase())
                    || n.tags
                        .iter()
                        .any(|t| t.to_lowercase().contains(&topic.to_lowercase()))
            })
            .take(10)
            .collect();

        if results.is_empty() {
            related_text.push_str(&format!("No nodes found matching '{}'.\n", topic));
        } else {
            for node in results {
                related_text.push_str(&format!(
                    "- **{}** ({:?})\n  ID: {}\n",
                    node.title, node.node_type, node.id
                ));
            }
        }
    }

    Ok(vec![PromptMessage {
        role: "user".to_string(),
        content: PromptContent::Text { text: related_text },
    }])
}
