use anyhow::Result;
use std::path::Path;

use crate::types::Language;

pub mod javascript;
pub mod python;
pub mod go_parser;
pub mod java;
pub mod rust_parser;
pub mod c_cpp;
pub mod csharp;
pub mod php;
pub mod ruby;
pub mod shell;

// NOTE: The following parsers are temporarily disabled because their tree-sitter
// packages don't have compatible versions on crates.io. They use regex-based 
// scanning instead (handled in the scanner module).
// pub mod kotlin;
// pub mod swift;
// pub mod dart;
// pub mod scala;
// pub mod objective_c;
// pub mod perl;
// pub mod lua;

/// A parsed source file
#[derive(Debug)]
pub struct ParsedFile {
    pub language: Language,
    pub source: String,
    pub tree: tree_sitter::Tree,
}

/// Trait for language-specific parsers
pub trait LanguageParser {
    fn language(&self) -> Language;
    fn parse(&self, source: &str) -> Result<tree_sitter::Tree>;
    fn get_tree_sitter_language(&self) -> tree_sitter::Language;
}

/// Get the appropriate parser for a file
pub fn get_parser_for_file(path: &Path) -> Option<Box<dyn LanguageParser>> {
    let ext = path.extension()?.to_str()?;
    get_parser_for_extension(ext)
}

/// Get parser by file extension
pub fn get_parser_for_extension(ext: &str) -> Option<Box<dyn LanguageParser>> {
    match ext.to_lowercase().as_str() {
        "js" | "jsx" | "mjs" | "cjs" => Some(Box::new(javascript::JavaScriptParser::new())),
        "ts" | "tsx" | "mts" | "cts" => Some(Box::new(javascript::TypeScriptParser::new())),
        "py" | "pyw" | "pyi" => Some(Box::new(python::PythonParser::new())),
        "go" => Some(Box::new(go_parser::GoParser::new())),
        "java" => Some(Box::new(java::JavaParser::new())),
        "rs" => Some(Box::new(rust_parser::RustParser::new())),
        "c" | "h" => Some(Box::new(c_cpp::CParser::new())),
        "cpp" | "cc" | "cxx" | "hpp" | "hxx" => Some(Box::new(c_cpp::CppParser::new())),
        "cs" => Some(Box::new(csharp::CSharpParser::new())),
        "php" => Some(Box::new(php::PhpParser::new())),
        "rb" => Some(Box::new(ruby::RubyParser::new())),
        "sh" | "bash" | "zsh" => Some(Box::new(shell::ShellParser::new())),
        // These languages use regex-based scanning (no tree-sitter parser available)
        // "kt" | "kts" => handled by regex scanner
        // "swift" => handled by regex scanner
        // "dart" => handled by regex scanner
        // "scala" | "sc" => handled by regex scanner
        // "m" | "mm" => handled by regex scanner
        // "pl" | "pm" => handled by regex scanner
        // "lua" => handled by regex scanner
        _ => None,
    }
}

/// Parse a file and return the AST
pub fn parse_file(path: &Path, source: &str) -> Result<ParsedFile> {
    let parser = get_parser_for_file(path)
        .ok_or_else(|| anyhow::anyhow!("Unsupported file type: {:?}", path))?;

    let tree = parser.parse(source)?;

    Ok(ParsedFile {
        language: parser.language(),
        source: source.to_string(),
        tree,
    })
}

/// Helper to create a tree-sitter parser
fn create_parser(language: tree_sitter::Language) -> Result<tree_sitter::Parser> {
    let mut parser = tree_sitter::Parser::new();
    parser.set_language(language)?;
    Ok(parser)
}
