"""Python dead code parser."""

from __future__ import annotations

from tree_sitter import Node

from vibelexity.parsers.python import PY_LANGUAGE
from vibelexity.patterns.common import create_query, run_captures
from vibelexity.dead_code.parsers.base import (
    SymbolDefinition,
    ImportedSymbol,
    VariableDefinition,
    SymbolReference,
    DeadCodeParser,
)


class PythonDeadCodeParser(DeadCodeParser):
    def _get_language(self):
        return PY_LANGUAGE

    def extract_imports(self, root: Node, source: str) -> list[ImportedSymbol]:
        queries = [
            "(import_statement (dotted_name (identifier) @import_name))",
            "(import_statement (aliased_import name: (dotted_name (identifier) @import_name) alias: (identifier) @import_alias))",
            "(import_from_statement name: (dotted_name (identifier) @import_name))",
            "(import_from_statement (aliased_import name: (identifier) @import_name alias: (identifier) @import_alias))",
        ]

        imports = []
        for query_str in queries:
            try:
                query = create_query(PY_LANGUAGE, query_str)
                captures = run_captures(query, root)

                for node, capture_name in captures:
                    text = node.text.decode() if node.text else ""
                    if capture_name == "import_name":
                        imports.append(
                            ImportedSymbol(
                                name=text,
                                line=node.start_point[0] + 1,
                                imported_from=None,
                                alias=None,
                            )
                        )
                    elif capture_name == "import_alias":
                        if imports:
                            imports[-1].alias = text
            except Exception:
                pass
        return imports

    def extract_definitions(self, root: Node, source: str) -> list[SymbolDefinition]:
        query_str = "(function_definition name: (identifier) @func_name) (class_definition name: (identifier) @class_name)"
        query = create_query(PY_LANGUAGE, query_str)
        captures = run_captures(query, root)

        defs = []
        for node, capture_name in captures:
            text = node.text.decode() if node.text else ""
            if capture_name == "func_name":
                defs.append(SymbolDefinition(text, node.start_point[0] + 1, "function"))
            elif capture_name == "class_name":
                defs.append(SymbolDefinition(text, node.start_point[0] + 1, "class"))
        return defs

    def _extract_abstract_classes(self, root: Node) -> set[str]:
        """Find classes that inherit from ABC."""
        abstract_classes = set()
        query_str = """(class_definition
            name: (identifier) @class_name
            (argument_list (identifier) @base_name))"""
        try:
            query = create_query(PY_LANGUAGE, query_str)
            captures = run_captures(query, root)
            current_class = None
            for node, capture_name in captures:
                text = node.text.decode() if node.text else ""
                if capture_name == "class_name":
                    current_class = text
                elif capture_name == "base_name" and text in ("ABC", "ABCMeta"):
                    if current_class:
                        abstract_classes.add(current_class)
        except Exception:
            pass
        return abstract_classes

    def _extract_abstract_methods(self, root: Node, source: str) -> set[str]:
        """Find methods with @abstractmethod decorator."""
        abstract_methods = set()
        source_lines = source.split("\n")
        query_str = """(decorator (identifier) @decorator_name)"""
        try:
            query = create_query(PY_LANGUAGE, query_str)
            captures = run_captures(query, root)
            for node, capture_name in captures:
                text = node.text.decode() if node.text else ""
                if capture_name == "decorator_name" and text in (
                    "abstractmethod",
                    "abstractproperty",
                    "abstractclassmethod",
                    "abstractstaticmethod",
                ):
                    line_num = node.start_point[0] + 1
                    if line_num < len(source_lines):
                        next_line = source_lines[line_num]
                        if next_line and "def " in next_line:
                            parts = next_line.split("def ")
                            if len(parts) > 1:
                                method_name = parts[1].split("(")[0].strip()
                                if method_name:
                                    abstract_methods.add(method_name)
        except Exception:
            pass
        return abstract_methods

    def extract_abstract_info(
        self, root: Node, source: str
    ) -> tuple[set[str], set[str]]:
        """Extract abstract class names and abstract method names."""
        abstract_classes = self._extract_abstract_classes(root)
        abstract_methods = self._extract_abstract_methods(root, source)
        return abstract_classes, abstract_methods
