use std::path::Path;

use compliance_core::models::graph::CodeNode;

/// A chunk of code extracted from a source file, ready for embedding
#[derive(Debug, Clone)]
pub struct CodeChunk {
    pub qualified_name: String,
    pub kind: String,
    pub file_path: String,
    pub start_line: u32,
    pub end_line: u32,
    pub language: String,
    pub content: String,
    pub context_header: String,
    pub token_estimate: u32,
}

/// Extract embeddable code chunks from parsed CodeNodes.
///
/// For each node, reads the corresponding source lines from disk,
/// builds a context header, and estimates tokens.
pub fn extract_chunks(
    repo_path: &Path,
    nodes: &[CodeNode],
    max_chunk_tokens: u32,
) -> Vec<CodeChunk> {
    let mut chunks = Vec::new();

    for node in nodes {
        let file = repo_path.join(&node.file_path);
        let source = match std::fs::read_to_string(&file) {
            Ok(s) => s,
            Err(_) => continue,
        };

        let lines: Vec<&str> = source.lines().collect();
        let start = node.start_line.saturating_sub(1) as usize;
        let end = (node.end_line as usize).min(lines.len());
        if start >= end {
            continue;
        }

        let content: String = lines[start..end].join("\n");

        // Skip tiny chunks
        if content.len() < 50 {
            continue;
        }

        // Estimate tokens (~4 chars per token)
        let mut token_estimate = (content.len() / 4) as u32;

        // Truncate if too large
        let final_content = if token_estimate > max_chunk_tokens {
            let max_chars = (max_chunk_tokens as usize) * 4;
            token_estimate = max_chunk_tokens;
            content.chars().take(max_chars).collect()
        } else {
            content
        };

        // Build context header: file path + containing scope hint
        let context_header = build_context_header(
            &node.file_path,
            &node.qualified_name,
            &node.kind.to_string(),
        );

        chunks.push(CodeChunk {
            qualified_name: node.qualified_name.clone(),
            kind: node.kind.to_string(),
            file_path: node.file_path.clone(),
            start_line: node.start_line,
            end_line: node.end_line,
            language: node.language.clone(),
            content: final_content,
            context_header,
            token_estimate,
        });
    }

    chunks
}

fn build_context_header(file_path: &str, qualified_name: &str, kind: &str) -> String {
    // Extract containing module/class from qualified name
    // e.g. "src/main.rs::MyStruct::my_method" → parent is "MyStruct"
    let parts: Vec<&str> = qualified_name.split("::").collect();
    if parts.len() >= 2 {
        let parent = parts[..parts.len() - 1].join("::");
        format!("// {file_path} | {kind} in {parent}")
    } else {
        format!("// {file_path} | {kind}")
    }
}
