//! Supported programming languages for syntax highlighting

/// Supported languages for syntax highlighting
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Language {
    /// Rust programming language
    Rust,
    /// Python programming language
    Python,
    /// JavaScript programming language
    JavaScript,
    /// TypeScript programming language
    TypeScript,
    /// Go programming language
    Go,
    /// C programming language
    C,
    /// C++ programming language
    Cpp,
    /// Java programming language
    Java,
    /// Ruby programming language
    Ruby,
    /// Shell/Bash scripting
    Shell,
    /// JSON data format
    Json,
    /// YAML data format
    Yaml,
    /// TOML configuration format
    Toml,
    /// Markdown markup language
    Markdown,
    /// SQL query language
    Sql,
    /// HTML markup language
    Html,
    /// CSS stylesheet language
    Css,
    /// Unknown or unsupported language
    Unknown,
}

impl Language {
    /// Detect language from code fence string
    pub fn from_fence(fence: &str) -> Self {
        let fence = fence.to_lowercase();
        match fence.as_str() {
            "rust" | "rs" => Self::Rust,
            "python" | "py" => Self::Python,
            "javascript" | "js" => Self::JavaScript,
            "typescript" | "ts" => Self::TypeScript,
            "go" | "golang" => Self::Go,
            "c" => Self::C,
            "c++" | "cpp" | "cxx" => Self::Cpp,
            "java" => Self::Java,
            "ruby" | "rb" => Self::Ruby,
            "shell" | "bash" | "sh" | "zsh" => Self::Shell,
            "json" => Self::Json,
            "yaml" | "yml" => Self::Yaml,
            "toml" => Self::Toml,
            "markdown" | "md" => Self::Markdown,
            "sql" => Self::Sql,
            "html" | "htm" => Self::Html,
            "css" => Self::Css,
            _ => Self::Unknown,
        }
    }

    /// Get keywords for this language
    pub(super) fn keywords(&self) -> &'static [&'static str] {
        match self {
            Self::Rust => &[
                "fn", "let", "mut", "const", "static", "if", "else", "match", "for", "while",
                "loop", "break", "continue", "return", "pub", "use", "mod", "struct", "enum",
                "impl", "trait", "type", "where", "as", "in", "ref", "self", "Self", "super",
                "crate", "async", "await", "dyn", "move", "unsafe", "extern", "true", "false",
            ],
            Self::Python => &[
                "def", "class", "if", "elif", "else", "for", "while", "try", "except", "finally",
                "with", "as", "import", "from", "return", "yield", "raise", "pass", "break",
                "continue", "and", "or", "not", "in", "is", "lambda", "True", "False", "None",
                "global", "nonlocal", "assert", "async", "await",
            ],
            Self::JavaScript | Self::TypeScript => &[
                "function",
                "const",
                "let",
                "var",
                "if",
                "else",
                "for",
                "while",
                "do",
                "switch",
                "case",
                "default",
                "break",
                "continue",
                "return",
                "try",
                "catch",
                "finally",
                "throw",
                "new",
                "delete",
                "typeof",
                "instanceof",
                "in",
                "of",
                "class",
                "extends",
                "super",
                "this",
                "import",
                "export",
                "from",
                "as",
                "async",
                "await",
                "yield",
                "true",
                "false",
                "null",
                "undefined",
            ],
            Self::Go => &[
                "func",
                "var",
                "const",
                "type",
                "struct",
                "interface",
                "map",
                "chan",
                "if",
                "else",
                "for",
                "range",
                "switch",
                "case",
                "default",
                "break",
                "continue",
                "return",
                "go",
                "defer",
                "select",
                "package",
                "import",
                "true",
                "false",
                "nil",
            ],
            Self::C | Self::Cpp => &[
                "if",
                "else",
                "for",
                "while",
                "do",
                "switch",
                "case",
                "default",
                "break",
                "continue",
                "return",
                "goto",
                "sizeof",
                "typedef",
                "struct",
                "union",
                "enum",
                "static",
                "extern",
                "const",
                "volatile",
                "register",
                "auto",
                "inline",
                "true",
                "false",
                "NULL",
                "nullptr",
                // C++ specific
                "class",
                "public",
                "private",
                "protected",
                "virtual",
                "override",
                "final",
                "new",
                "delete",
                "this",
                "namespace",
                "using",
                "template",
                "typename",
                "try",
                "catch",
                "throw",
                "noexcept",
                "constexpr",
            ],
            Self::Java => &[
                "class",
                "interface",
                "extends",
                "implements",
                "public",
                "private",
                "protected",
                "static",
                "final",
                "abstract",
                "synchronized",
                "volatile",
                "transient",
                "if",
                "else",
                "for",
                "while",
                "do",
                "switch",
                "case",
                "default",
                "break",
                "continue",
                "return",
                "try",
                "catch",
                "finally",
                "throw",
                "throws",
                "new",
                "this",
                "super",
                "instanceof",
                "import",
                "package",
                "true",
                "false",
                "null",
            ],
            Self::Ruby => &[
                "def", "class", "module", "if", "elsif", "else", "unless", "case", "when", "while",
                "until", "for", "do", "end", "begin", "rescue", "ensure", "raise", "return",
                "yield", "break", "next", "redo", "retry", "self", "super", "true", "false", "nil",
                "and", "or", "not", "in", "then",
            ],
            Self::Shell => &[
                "if", "then", "else", "elif", "fi", "case", "esac", "for", "while", "until", "do",
                "done", "in", "function", "return", "exit", "break", "continue", "export", "local",
                "readonly", "unset", "true", "false",
            ],
            Self::Sql => &[
                "SELECT",
                "FROM",
                "WHERE",
                "AND",
                "OR",
                "NOT",
                "IN",
                "LIKE",
                "BETWEEN",
                "JOIN",
                "LEFT",
                "RIGHT",
                "INNER",
                "OUTER",
                "ON",
                "GROUP",
                "BY",
                "HAVING",
                "ORDER",
                "ASC",
                "DESC",
                "LIMIT",
                "OFFSET",
                "INSERT",
                "INTO",
                "VALUES",
                "UPDATE",
                "SET",
                "DELETE",
                "CREATE",
                "TABLE",
                "DROP",
                "ALTER",
                "INDEX",
                "PRIMARY",
                "KEY",
                "FOREIGN",
                "REFERENCES",
                "NULL",
                "DEFAULT",
                "UNIQUE",
                "AS",
                "DISTINCT",
                "COUNT",
                "SUM",
                "AVG",
                "MIN",
                "MAX",
                "CASE",
                "WHEN",
                "THEN",
                "ELSE",
                "END",
                "UNION",
                "ALL",
                "EXISTS",
            ],
            _ => &[],
        }
    }

    /// Get type keywords for this language
    pub(super) fn types(&self) -> &'static [&'static str] {
        match self {
            Self::Rust => &[
                "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128",
                "usize", "f32", "f64", "bool", "char", "str", "String", "Vec", "Box", "Rc", "Arc",
                "Option", "Result", "HashMap", "HashSet", "BTreeMap", "BTreeSet",
            ],
            Self::Python => &[
                "int",
                "float",
                "str",
                "bool",
                "list",
                "dict",
                "set",
                "tuple",
                "bytes",
                "bytearray",
                "object",
                "type",
            ],
            Self::JavaScript | Self::TypeScript => &[
                "number", "string", "boolean", "object", "Array", "Map", "Set", "Promise", "Date",
                "RegExp", "Error", "Symbol", "BigInt", "void", "any", "unknown", "never",
            ],
            Self::Go => &[
                "int",
                "int8",
                "int16",
                "int32",
                "int64",
                "uint",
                "uint8",
                "uint16",
                "uint32",
                "uint64",
                "float32",
                "float64",
                "complex64",
                "complex128",
                "bool",
                "byte",
                "rune",
                "string",
                "error",
            ],
            Self::C | Self::Cpp => &[
                "int",
                "long",
                "short",
                "char",
                "float",
                "double",
                "void",
                "signed",
                "unsigned",
                "bool",
                "size_t",
                "ptrdiff_t",
                "int8_t",
                "int16_t",
                "int32_t",
                "int64_t",
                "uint8_t",
                "uint16_t",
                "uint32_t",
                "uint64_t",
                "string",
                "vector",
                "map",
                "set",
                "array",
                "deque",
                "list",
            ],
            Self::Java => &[
                "int", "long", "short", "byte", "float", "double", "char", "boolean", "void",
                "String", "Integer", "Long", "Double", "Boolean", "Object", "List", "Map", "Set",
                "Array",
            ],
            Self::Ruby => &[
                "Integer",
                "Float",
                "String",
                "Array",
                "Hash",
                "Symbol",
                "TrueClass",
                "FalseClass",
                "NilClass",
                "Object",
                "Class",
            ],
            Self::Sql => &[
                "INT",
                "INTEGER",
                "BIGINT",
                "SMALLINT",
                "TINYINT",
                "FLOAT",
                "DOUBLE",
                "DECIMAL",
                "NUMERIC",
                "VARCHAR",
                "CHAR",
                "TEXT",
                "BLOB",
                "DATE",
                "TIME",
                "DATETIME",
                "TIMESTAMP",
                "BOOLEAN",
                "BOOL",
            ],
            _ => &[],
        }
    }

    /// Get comment patterns for this language
    pub(super) fn comment_patterns(&self) -> (&'static str, Option<(&'static str, &'static str)>) {
        match self {
            Self::Rust
            | Self::Go
            | Self::C
            | Self::Cpp
            | Self::Java
            | Self::JavaScript
            | Self::TypeScript
            | Self::Css => ("//", Some(("/*", "*/"))),
            Self::Python | Self::Ruby | Self::Shell | Self::Yaml | Self::Toml => ("#", None),
            Self::Sql => ("--", Some(("/*", "*/"))),
            Self::Html => ("", Some(("<!--", "-->"))),
            _ => ("//", None),
        }
    }
}
