pub mod bash;
pub mod c;
pub mod clojure;
pub mod cpp;
pub mod csharp;
pub mod cuda;
pub mod dart;
pub mod elixir;
pub mod erlang;
pub mod fsharp;
pub mod gleam;
pub mod go;
pub mod groovy;
pub mod haskell;
pub mod hcl;
pub mod helpers;
pub mod java;
pub mod javascript;
pub mod julia;
pub mod kotlin;
pub mod lua;
pub mod objc;
pub mod ocaml;
pub mod php;
pub mod python;
pub mod r_lang;
pub mod ruby;
pub mod rust_lang;
pub mod scala;
pub mod solidity;
pub mod swift;
pub mod verilog;
pub mod zig;

use crate::parser_registry::LanguageKind;
use crate::types::FileSymbols;
use tree_sitter::Tree;

/// Trait every language extractor implements.
pub trait SymbolExtractor {
    fn extract(&self, tree: &Tree, source: &[u8], file_path: &str) -> FileSymbols;
    /// Extract with optional AST node collection. Default delegates to `extract`.
    fn extract_with_opts(
        &self,
        tree: &Tree,
        source: &[u8],
        file_path: &str,
        include_ast_nodes: bool,
    ) -> FileSymbols {
        let mut symbols = self.extract(tree, source, file_path);
        if !include_ast_nodes {
            symbols.ast_nodes.clear();
        }
        symbols
    }
}

/// Dispatch to the correct extractor based on language kind.
pub fn extract_symbols(
    lang: LanguageKind,
    tree: &Tree,
    source: &[u8],
    file_path: &str,
) -> FileSymbols {
    extract_symbols_with_opts(lang, tree, source, file_path, true)
}

/// Dispatch with optional AST node extraction.
pub fn extract_symbols_with_opts(
    lang: LanguageKind,
    tree: &Tree,
    source: &[u8],
    file_path: &str,
    include_ast_nodes: bool,
) -> FileSymbols {
    match lang {
        LanguageKind::JavaScript | LanguageKind::TypeScript | LanguageKind::Tsx => {
            javascript::JsExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Python => {
            python::PythonExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Go => {
            go::GoExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Rust => {
            rust_lang::RustExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Java => {
            java::JavaExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::CSharp => {
            csharp::CSharpExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Ruby => {
            ruby::RubyExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Php => {
            php::PhpExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Hcl => {
            hcl::HclExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::C => {
            c::CExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Cpp => {
            cpp::CppExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Kotlin => {
            kotlin::KotlinExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Swift => {
            swift::SwiftExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Scala => {
            scala::ScalaExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Bash => {
            bash::BashExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Elixir => {
            elixir::ElixirExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Lua => {
            lua::LuaExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Julia => {
            julia::JuliaExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Dart => {
            dart::DartExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Zig => {
            zig::ZigExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Haskell => {
            haskell::HaskellExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Ocaml | LanguageKind::OcamlInterface => {
            ocaml::OcamlExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::FSharp | LanguageKind::FSharpSignature => {
            fsharp::FSharpExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::ObjC => {
            objc::ObjCExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Gleam => {
            gleam::GleamExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Cuda => {
            cuda::CudaExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Clojure => {
            clojure::ClojureExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Erlang => {
            erlang::ErlangExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Groovy => {
            groovy::GroovyExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::R => {
            r_lang::RExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Solidity => {
            solidity::SolidityExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
        LanguageKind::Verilog => {
            verilog::VerilogExtractor.extract_with_opts(tree, source, file_path, include_ast_nodes)
        }
    }
}
