"""Language registry — 10 languages with tree-sitter AST specs."""

from dataclasses import dataclass, field
from typing import Optional


@dataclass
class LanguageSpec:
    """Specification for extracting symbols from a language's AST."""

    ts_language: str
    symbol_node_types: dict[str, str]
    name_fields: dict[str, str]
    param_fields: dict[str, str] = field(default_factory=dict)
    return_type_fields: dict[str, str] = field(default_factory=dict)
    docstring_strategy: str = 'preceding_comment'
    decorator_node_type: Optional[str] = None
    container_node_types: list[str] = field(default_factory=list)
    constant_patterns: list[str] = field(default_factory=list)
    type_patterns: list[str] = field(default_factory=list)
    # Node types containing call expressions
    call_node_types: list[str] = field(
        default_factory=lambda: ['call_expression']
    )
    # How to extract callee name from a call node
    callee_field: str = 'function'


LANGUAGE_EXTENSIONS: dict[str, str] = {
    '.py': 'python',
    '.js': 'javascript',
    '.jsx': 'javascript',
    '.ts': 'typescript',
    '.tsx': 'typescript',
    '.go': 'go',
    '.rs': 'rust',
    '.java': 'java',
    '.c': 'c',
    '.h': 'c',
    '.cc': 'cpp',
    '.cpp': 'cpp',
    '.cxx': 'cpp',
    '.hpp': 'cpp',
    '.hh': 'cpp',
    '.cs': 'c_sharp',
    '.rb': 'ruby',
}


# --- Python ---
PYTHON_SPEC = LanguageSpec(
    ts_language='python',
    symbol_node_types={
        'function_definition': 'function',
        'class_definition': 'class',
    },
    name_fields={
        'function_definition': 'name',
        'class_definition': 'name',
    },
    param_fields={'function_definition': 'parameters'},
    return_type_fields={'function_definition': 'return_type'},
    docstring_strategy='next_sibling_string',
    decorator_node_type='decorator',
    container_node_types=['class_definition'],
    constant_patterns=['assignment'],
    type_patterns=['type_alias_statement'],
    call_node_types=['call'],
    callee_field='function',
)


# --- JavaScript ---
JAVASCRIPT_SPEC = LanguageSpec(
    ts_language='javascript',
    symbol_node_types={
        'function_declaration': 'function',
        'class_declaration': 'class',
        'method_definition': 'method',
        'generator_function_declaration': 'function',
    },
    name_fields={
        'function_declaration': 'name',
        'class_declaration': 'name',
        'method_definition': 'name',
    },
    param_fields={
        'function_declaration': 'parameters',
        'method_definition': 'parameters',
    },
    docstring_strategy='preceding_comment',
    container_node_types=['class_declaration', 'class'],
    constant_patterns=['lexical_declaration'],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- TypeScript ---
TYPESCRIPT_SPEC = LanguageSpec(
    ts_language='typescript',
    symbol_node_types={
        'function_declaration': 'function',
        'class_declaration': 'class',
        'method_definition': 'method',
        'interface_declaration': 'interface',
        'type_alias_declaration': 'type',
        'enum_declaration': 'type',
    },
    name_fields={
        'function_declaration': 'name',
        'class_declaration': 'name',
        'method_definition': 'name',
        'interface_declaration': 'name',
        'type_alias_declaration': 'name',
        'enum_declaration': 'name',
    },
    param_fields={
        'function_declaration': 'parameters',
        'method_definition': 'parameters',
    },
    return_type_fields={
        'function_declaration': 'return_type',
        'method_definition': 'return_type',
    },
    docstring_strategy='preceding_comment',
    decorator_node_type='decorator',
    container_node_types=['class_declaration', 'class'],
    constant_patterns=['lexical_declaration'],
    type_patterns=[
        'interface_declaration',
        'type_alias_declaration',
        'enum_declaration',
    ],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- Go ---
GO_SPEC = LanguageSpec(
    ts_language='go',
    symbol_node_types={
        'function_declaration': 'function',
        'method_declaration': 'method',
        'type_declaration': 'type',
    },
    name_fields={
        'function_declaration': 'name',
        'method_declaration': 'name',
        'type_declaration': 'name',
    },
    param_fields={
        'function_declaration': 'parameters',
        'method_declaration': 'parameters',
    },
    return_type_fields={
        'function_declaration': 'result',
        'method_declaration': 'result',
    },
    docstring_strategy='preceding_comment',
    container_node_types=[],
    constant_patterns=['const_declaration'],
    type_patterns=['type_declaration'],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- Rust ---
RUST_SPEC = LanguageSpec(
    ts_language='rust',
    symbol_node_types={
        'function_item': 'function',
        'struct_item': 'type',
        'enum_item': 'type',
        'trait_item': 'type',
        'impl_item': 'class',
        'type_item': 'type',
    },
    name_fields={
        'function_item': 'name',
        'struct_item': 'name',
        'enum_item': 'name',
        'trait_item': 'name',
        'type_item': 'name',
    },
    param_fields={'function_item': 'parameters'},
    return_type_fields={'function_item': 'return_type'},
    docstring_strategy='preceding_comment',
    decorator_node_type='attribute_item',
    container_node_types=['impl_item', 'trait_item'],
    constant_patterns=['const_item', 'static_item'],
    type_patterns=['struct_item', 'enum_item', 'trait_item', 'type_item'],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- Java ---
JAVA_SPEC = LanguageSpec(
    ts_language='java',
    symbol_node_types={
        'method_declaration': 'method',
        'constructor_declaration': 'method',
        'class_declaration': 'class',
        'interface_declaration': 'interface',
        'enum_declaration': 'type',
    },
    name_fields={
        'method_declaration': 'name',
        'constructor_declaration': 'name',
        'class_declaration': 'name',
        'interface_declaration': 'name',
        'enum_declaration': 'name',
    },
    param_fields={
        'method_declaration': 'parameters',
        'constructor_declaration': 'parameters',
    },
    return_type_fields={'method_declaration': 'type'},
    docstring_strategy='preceding_comment',
    decorator_node_type='marker_annotation',
    container_node_types=[
        'class_declaration',
        'interface_declaration',
        'enum_declaration',
    ],
    constant_patterns=['field_declaration'],
    type_patterns=['interface_declaration', 'enum_declaration'],
    call_node_types=['method_invocation'],
    callee_field='name',
)


# --- C ---
C_SPEC = LanguageSpec(
    ts_language='c',
    symbol_node_types={
        'function_definition': 'function',
        'struct_specifier': 'type',
        'enum_specifier': 'type',
        'type_definition': 'type',
    },
    name_fields={
        'function_definition': 'declarator',
        'struct_specifier': 'name',
        'enum_specifier': 'name',
        'type_definition': 'declarator',
    },
    param_fields={'function_definition': 'declarator'},
    docstring_strategy='preceding_comment',
    constant_patterns=['preproc_def'],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- C++ ---
CPP_SPEC = LanguageSpec(
    ts_language='cpp',
    symbol_node_types={
        'function_definition': 'function',
        'class_specifier': 'class',
        'struct_specifier': 'type',
        'enum_specifier': 'type',
        'type_definition': 'type',
        'namespace_definition': 'type',
    },
    name_fields={
        'function_definition': 'declarator',
        'class_specifier': 'name',
        'struct_specifier': 'name',
        'enum_specifier': 'name',
        'type_definition': 'declarator',
        'namespace_definition': 'name',
    },
    param_fields={'function_definition': 'declarator'},
    docstring_strategy='preceding_comment',
    container_node_types=['class_specifier', 'struct_specifier', 'namespace_definition'],
    constant_patterns=['preproc_def'],
    call_node_types=['call_expression'],
    callee_field='function',
)


# --- C# ---
CSHARP_SPEC = LanguageSpec(
    ts_language='c_sharp',
    symbol_node_types={
        'method_declaration': 'method',
        'constructor_declaration': 'method',
        'class_declaration': 'class',
        'interface_declaration': 'interface',
        'enum_declaration': 'type',
        'struct_declaration': 'type',
        'record_declaration': 'type',
    },
    name_fields={
        'method_declaration': 'name',
        'constructor_declaration': 'name',
        'class_declaration': 'name',
        'interface_declaration': 'name',
        'enum_declaration': 'name',
        'struct_declaration': 'name',
        'record_declaration': 'name',
    },
    param_fields={
        'method_declaration': 'parameters',
        'constructor_declaration': 'parameters',
    },
    return_type_fields={'method_declaration': 'type'},
    docstring_strategy='preceding_comment',
    decorator_node_type='attribute_list',
    container_node_types=[
        'class_declaration',
        'interface_declaration',
        'struct_declaration',
    ],
    constant_patterns=['field_declaration'],
    type_patterns=[
        'interface_declaration',
        'enum_declaration',
        'struct_declaration',
    ],
    call_node_types=['invocation_expression'],
    callee_field='function',
)


# --- Ruby ---
RUBY_SPEC = LanguageSpec(
    ts_language='ruby',
    symbol_node_types={
        'method': 'function',
        'singleton_method': 'function',
        'class': 'class',
        'module': 'class',
    },
    name_fields={
        'method': 'name',
        'singleton_method': 'name',
        'class': 'name',
        'module': 'name',
    },
    param_fields={
        'method': 'parameters',
        'singleton_method': 'parameters',
    },
    docstring_strategy='preceding_comment',
    container_node_types=['class', 'module'],
    constant_patterns=['assignment'],
    call_node_types=['call', 'method_call'],
    callee_field='method',
)


LANGUAGE_REGISTRY: dict[str, LanguageSpec] = {
    'python': PYTHON_SPEC,
    'javascript': JAVASCRIPT_SPEC,
    'typescript': TYPESCRIPT_SPEC,
    'go': GO_SPEC,
    'rust': RUST_SPEC,
    'java': JAVA_SPEC,
    'c': C_SPEC,
    'cpp': CPP_SPEC,
    'c_sharp': CSHARP_SPEC,
    'ruby': RUBY_SPEC,
}
