//! Thread-safe grammar store for caching compiled grammars.
//!
//! The `GrammarStore` holds compiled grammars that can be shared across threads.
//! Each grammar is compiled once and cached for reuse.
//!
//! # Generated Code
//!
//! This file is automatically generated from the grammar registry
//! (`langs/group-*/*/def/arborium.kdl`). Do not edit manually.

use std::borrow::Cow;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};

#[allow(unused_imports)]
use arborium_highlight::tree_sitter::{CompiledGrammar, GrammarConfig};

/// Thread-safe cache of compiled grammars.
///
/// Grammars are compiled on first access and cached. The store can be shared
/// across threads via `Arc<GrammarStore>`.
///
/// # Example
///
/// ```rust,ignore
/// use std::sync::Arc;
///
/// // Create store (automatically populated with available grammars)
/// let store = Arc::new(GrammarStore::new());
///
/// // Share across threads
/// let store2 = store.clone();
/// std::thread::spawn(move || {
///     let grammar = store2.get("rust").unwrap();
///     // Use grammar...
/// });
/// ```
pub struct GrammarStore {
    grammars: RwLock<HashMap<String, Arc<CompiledGrammar>>>,
}

impl Default for GrammarStore {
    fn default() -> Self {
        Self::new()
    }
}

impl GrammarStore {
    /// Create a new empty grammar store.
    pub fn new() -> Self {
        Self {
            grammars: RwLock::new(HashMap::new()),
        }
    }

    /// Get a grammar by language name, compiling and caching it if needed.
    ///
    /// Returns `None` if the language is not supported.
    pub fn get(&self, language: &str) -> Option<Arc<CompiledGrammar>> {
        let normalized = Self::normalize_language(language);

        // Fast path: check if already cached
        {
            let grammars = self.grammars.read().unwrap();
            if let Some(grammar) = grammars.get(&*normalized) {
                return Some(grammar.clone());
            }
        }

        // Slow path: compile and cache
        let grammar = Self::compile_grammar(&normalized)?;
        let grammar = Arc::new(grammar);

        {
            let mut grammars = self.grammars.write().unwrap();
            // Double-check in case another thread compiled it
            if let Some(existing) = grammars.get(&*normalized) {
                return Some(existing.clone());
            }
            grammars.insert(normalized.into_owned(), grammar.clone());
        }

        Some(grammar)
    }

    /// Normalize a language name to its canonical form.
    fn normalize_language(language: &str) -> Cow<'_, str> {
        match language {
            // Aliases (generated from arborium.kdl)

            "adoc" => Cow::Borrowed("asciidoc"),

            "assembly" => Cow::Borrowed("asm"),

            "bat" => Cow::Borrowed("batch"),

            "bazel" => Cow::Borrowed("starlark"),

            "bzl" => Cow::Borrowed("starlark"),

            "c++" => Cow::Borrowed("cpp"),

            "cfg" => Cow::Borrowed("ini"),

            "cjs" => Cow::Borrowed("javascript"),

            "cl" => Cow::Borrowed("commonlisp"),

            "clj" => Cow::Borrowed("clojure"),

            "cmd" => Cow::Borrowed("batch"),

            "conf" => Cow::Borrowed("ini"),

            "cs" => Cow::Borrowed("c-sharp"),

            "csharp" => Cow::Borrowed("c-sharp"),

            "cts" => Cow::Borrowed("typescript"),

            "cxx" => Cow::Borrowed("cpp"),

            "dlang" => Cow::Borrowed("d"),

            "docker" => Cow::Borrowed("dockerfile"),

            "el" => Cow::Borrowed("elisp"),

            "emacs-lisp" => Cow::Borrowed("elisp"),

            "erl" => Cow::Borrowed("erlang"),

            "ex" => Cow::Borrowed("elixir"),

            "exs" => Cow::Borrowed("elixir"),

            "f#" => Cow::Borrowed("fsharp"),

            "frag" => Cow::Borrowed("glsl"),

            "fs" => Cow::Borrowed("fsharp"),

            "golang" => Cow::Borrowed("go"),

            "gql" => Cow::Borrowed("graphql"),

            "gsh" => Cow::Borrowed("groovy"),

            "gvy" => Cow::Borrowed("groovy"),

            "gy" => Cow::Borrowed("groovy"),

            "h" => Cow::Borrowed("c"),

            "hpp" => Cow::Borrowed("cpp"),

            "hs" => Cow::Borrowed("haskell"),

            "htm" => Cow::Borrowed("html"),

            "idr" => Cow::Borrowed("idris"),

            "j2" => Cow::Borrowed("jinja2"),

            "jinja" => Cow::Borrowed("jinja2"),

            "jl" => Cow::Borrowed("julia"),

            "js" => Cow::Borrowed("javascript"),

            "jsonc" => Cow::Borrowed("json"),

            "jsx" => Cow::Borrowed("javascript"),

            "kt" => Cow::Borrowed("kotlin"),

            "kts" => Cow::Borrowed("kotlin"),

            "lisp" => Cow::Borrowed("commonlisp"),

            "m" => Cow::Borrowed("matlab"),

            "md" => Cow::Borrowed("markdown"),

            "mdx" => Cow::Borrowed("markdown"),

            "mjs" => Cow::Borrowed("javascript"),

            "ml" => Cow::Borrowed("ocaml"),

            "mm" => Cow::Borrowed("objc"),

            "mts" => Cow::Borrowed("typescript"),

            "mysql" => Cow::Borrowed("sql"),

            "nasm" => Cow::Borrowed("x86asm"),

            "objective-c" => Cow::Borrowed("objc"),

            "patch" => Cow::Borrowed("diff"),

            "pbtxt" => Cow::Borrowed("textproto"),

            "pl" => Cow::Borrowed("perl"),

            "pm" => Cow::Borrowed("perl"),

            "postgres" => Cow::Borrowed("sql"),

            "postgresql" => Cow::Borrowed("sql"),

            "pro" => Cow::Borrowed("prolog"),

            "ps" => Cow::Borrowed("postscript"),

            "ps1" => Cow::Borrowed("powershell"),

            "pwsh" => Cow::Borrowed("powershell"),

            "py" => Cow::Borrowed("python"),

            "py3" => Cow::Borrowed("python"),

            "python3" => Cow::Borrowed("python"),

            "rb" => Cow::Borrowed("ruby"),

            "res" => Cow::Borrowed("rescript"),

            "rkt" => Cow::Borrowed("scheme"),

            "rlang" => Cow::Borrowed("r"),

            "rq" => Cow::Borrowed("sparql"),

            "rs" => Cow::Borrowed("rust"),

            "sass" => Cow::Borrowed("scss"),

            "scm" => Cow::Borrowed("query"),

            "sh" => Cow::Borrowed("bash"),

            "shell" => Cow::Borrowed("bash"),

            "sqlite" => Cow::Borrowed("sql"),

            "ss" => Cow::Borrowed("scheme"),

            "sv" => Cow::Borrowed("verilog"),

            "svg" => Cow::Borrowed("xml"),

            "systemverilog" => Cow::Borrowed("verilog"),

            "terraform" => Cow::Borrowed("hcl"),

            "textpb" => Cow::Borrowed("textproto"),

            "tf" => Cow::Borrowed("hcl"),

            "tla" => Cow::Borrowed("tlaplus"),

            "ts" => Cow::Borrowed("typescript"),

            "typ" => Cow::Borrowed("typst"),

            "ua" => Cow::Borrowed("uiua"),

            "v" => Cow::Borrowed("verilog"),

            "vbnet" => Cow::Borrowed("vb"),

            "vert" => Cow::Borrowed("glsl"),

            "vhd" => Cow::Borrowed("vhdl"),

            "viml" => Cow::Borrowed("vim"),

            "vimscript" => Cow::Borrowed("vim"),

            "visualbasic" => Cow::Borrowed("vb"),

            "wasm-interface" => Cow::Borrowed("wit"),

            "x86" => Cow::Borrowed("x86asm"),

            "xsl" => Cow::Borrowed("xml"),

            "xslt" => Cow::Borrowed("xml"),

            "yml" => Cow::Borrowed("yaml"),

            // Unknown language names pass through as-is
            _ => Cow::Borrowed(language),
        }
    }

    /// Compile a grammar for a language.
    #[allow(unused_variables)]
    fn compile_grammar(language: &str) -> Option<CompiledGrammar> {
        macro_rules! try_lang {
            ($feature:literal, $module:ident, $primary:literal) => {
                #[cfg(feature = $feature)]
                if language == $primary {
                    let config = GrammarConfig {
                        language: crate::$module::language().into(),
                        highlights_query: &crate::$module::HIGHLIGHTS_QUERY,
                        injections_query: crate::$module::INJECTIONS_QUERY,
                        locals_query: crate::$module::LOCALS_QUERY,
                    };
                    return CompiledGrammar::new(config).ok();
                }
            };
        }

        // All languages (generated from arborium.kdl)

        try_lang!("lang-ada", lang_ada, "ada");

        try_lang!("lang-agda", lang_agda, "agda");

        try_lang!("lang-asciidoc", lang_asciidoc, "asciidoc");

        try_lang!("lang-asm", lang_asm, "asm");

        try_lang!("lang-awk", lang_awk, "awk");

        try_lang!("lang-bash", lang_bash, "bash");

        try_lang!("lang-batch", lang_batch, "batch");

        try_lang!("lang-c", lang_c, "c");

        try_lang!("lang-c-sharp", lang_c_sharp, "c-sharp");

        try_lang!("lang-caddy", lang_caddy, "caddy");

        try_lang!("lang-capnp", lang_capnp, "capnp");

        try_lang!("lang-clojure", lang_clojure, "clojure");

        try_lang!("lang-cmake", lang_cmake, "cmake");

        try_lang!("lang-commonlisp", lang_commonlisp, "commonlisp");

        try_lang!("lang-cpp", lang_cpp, "cpp");

        try_lang!("lang-css", lang_css, "css");

        try_lang!("lang-d", lang_d, "d");

        try_lang!("lang-dart", lang_dart, "dart");

        try_lang!("lang-devicetree", lang_devicetree, "devicetree");

        try_lang!("lang-diff", lang_diff, "diff");

        try_lang!("lang-dockerfile", lang_dockerfile, "dockerfile");

        try_lang!("lang-dot", lang_dot, "dot");

        try_lang!("lang-elisp", lang_elisp, "elisp");

        try_lang!("lang-elixir", lang_elixir, "elixir");

        try_lang!("lang-elm", lang_elm, "elm");

        try_lang!("lang-erlang", lang_erlang, "erlang");

        try_lang!("lang-fish", lang_fish, "fish");

        try_lang!("lang-fsharp", lang_fsharp, "fsharp");

        try_lang!("lang-gleam", lang_gleam, "gleam");

        try_lang!("lang-glsl", lang_glsl, "glsl");

        try_lang!("lang-go", lang_go, "go");

        try_lang!("lang-graphql", lang_graphql, "graphql");

        try_lang!("lang-groovy", lang_groovy, "groovy");

        try_lang!("lang-haskell", lang_haskell, "haskell");

        try_lang!("lang-hcl", lang_hcl, "hcl");

        try_lang!("lang-hlsl", lang_hlsl, "hlsl");

        try_lang!("lang-html", lang_html, "html");

        try_lang!("lang-idris", lang_idris, "idris");

        try_lang!("lang-ini", lang_ini, "ini");

        try_lang!("lang-java", lang_java, "java");

        try_lang!("lang-javascript", lang_javascript, "javascript");

        try_lang!("lang-jinja2", lang_jinja2, "jinja2");

        try_lang!("lang-jq", lang_jq, "jq");

        try_lang!("lang-json", lang_json, "json");

        try_lang!("lang-julia", lang_julia, "julia");

        try_lang!("lang-kdl", lang_kdl, "kdl");

        try_lang!("lang-kotlin", lang_kotlin, "kotlin");

        try_lang!("lang-lean", lang_lean, "lean");

        try_lang!("lang-lua", lang_lua, "lua");

        try_lang!("lang-markdown", lang_markdown, "markdown");

        try_lang!("lang-matlab", lang_matlab, "matlab");

        try_lang!("lang-meson", lang_meson, "meson");

        try_lang!("lang-nginx", lang_nginx, "nginx");

        try_lang!("lang-ninja", lang_ninja, "ninja");

        try_lang!("lang-nix", lang_nix, "nix");

        try_lang!("lang-objc", lang_objc, "objc");

        try_lang!("lang-ocaml", lang_ocaml, "ocaml");

        try_lang!("lang-perl", lang_perl, "perl");

        try_lang!("lang-php", lang_php, "php");

        try_lang!("lang-postscript", lang_postscript, "postscript");

        try_lang!("lang-powershell", lang_powershell, "powershell");

        try_lang!("lang-prolog", lang_prolog, "prolog");

        try_lang!("lang-python", lang_python, "python");

        try_lang!("lang-query", lang_query, "query");

        try_lang!("lang-r", lang_r, "r");

        try_lang!("lang-rescript", lang_rescript, "rescript");

        try_lang!("lang-ron", lang_ron, "ron");

        try_lang!("lang-ruby", lang_ruby, "ruby");

        try_lang!("lang-rust", lang_rust, "rust");

        try_lang!("lang-scala", lang_scala, "scala");

        try_lang!("lang-scheme", lang_scheme, "scheme");

        try_lang!("lang-scss", lang_scss, "scss");

        try_lang!("lang-sparql", lang_sparql, "sparql");

        try_lang!("lang-sql", lang_sql, "sql");

        try_lang!("lang-ssh-config", lang_ssh_config, "ssh-config");

        try_lang!("lang-starlark", lang_starlark, "starlark");

        try_lang!("lang-svelte", lang_svelte, "svelte");

        try_lang!("lang-swift", lang_swift, "swift");

        try_lang!("lang-textproto", lang_textproto, "textproto");

        try_lang!("lang-thrift", lang_thrift, "thrift");

        try_lang!("lang-tlaplus", lang_tlaplus, "tlaplus");

        try_lang!("lang-toml", lang_toml, "toml");

        try_lang!("lang-tsx", lang_tsx, "tsx");

        try_lang!("lang-typescript", lang_typescript, "typescript");

        try_lang!("lang-typst", lang_typst, "typst");

        try_lang!("lang-uiua", lang_uiua, "uiua");

        try_lang!("lang-vb", lang_vb, "vb");

        try_lang!("lang-verilog", lang_verilog, "verilog");

        try_lang!("lang-vhdl", lang_vhdl, "vhdl");

        try_lang!("lang-vim", lang_vim, "vim");

        try_lang!("lang-vue", lang_vue, "vue");

        try_lang!("lang-wit", lang_wit, "wit");

        try_lang!("lang-x86asm", lang_x86asm, "x86asm");

        try_lang!("lang-xml", lang_xml, "xml");

        try_lang!("lang-yaml", lang_yaml, "yaml");

        try_lang!("lang-yuri", lang_yuri, "yuri");

        try_lang!("lang-zig", lang_zig, "zig");

        try_lang!("lang-zsh", lang_zsh, "zsh");


        None
    }
}