"""TypeScript language adapter using tree-sitter.

Handles .ts and .tsx files using the tree-sitter-typescript grammar.
Uses shared parsing utilities from _treesitter_utils.py.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

import tree_sitter_typescript as tsts
from tree_sitter import Language, Parser

from unfamiliar.analysis.adapters._treesitter_utils import (
    calculate_complexity,
    resolve_js_ts_import,
)
from unfamiliar.analysis.adapters._ts_definitions import extract_definitions
from unfamiliar.analysis.adapters._ts_entry_points import extract_entry_points
from unfamiliar.analysis.adapters._ts_imports import extract_es_imports
from unfamiliar.analysis.models import ParsedFile

if TYPE_CHECKING:
    from collections.abc import Sequence
    from pathlib import Path

logger = logging.getLogger(__name__)

# Pre-create languages for performance
_TS_LANGUAGE = Language(tsts.language_typescript())
_TSX_LANGUAGE = Language(tsts.language_tsx())


class TypeScriptAdapter:
    """Language adapter for TypeScript source files using tree-sitter."""

    def __init__(self) -> None:
        self._ts_parser = Parser(_TS_LANGUAGE)
        self._tsx_parser = Parser(_TSX_LANGUAGE)

    def language_name(self) -> str:
        """Return the lowercase name of the language."""
        return "typescript"

    def supported_extensions(self) -> frozenset[str]:
        """Return supported file extensions."""
        return frozenset({".ts", ".tsx"})

    def resolution_extensions(self) -> Sequence[str]:
        """Extensions to try when resolving imports, in preference order.

        TS adapter prefers .ts/.tsx over .js/.jsx
        """
        return [
            ".ts",
            ".tsx",
            ".js",
            ".jsx",
        ]

    def can_handle(self, path: str) -> bool:
        """Check if this adapter can parse the given file."""
        return path.endswith((".ts", ".tsx"))

    def parse_file(self, path: Path, content: bytes) -> ParsedFile:
        """Parse a TypeScript file and extract structure.

        Args:
            path: Relative path to the file.
            content: Raw file contents as bytes.

        Returns:
            ParsedFile with imports, definitions, entry points, and complexity.
            Returns empty ParsedFile on parse errors (logs warning).
        """
        path_str = str(path)

        line_count = content.count(b"\n") + 1 if content else 0

        # Select correct parser based on extension
        parser = self._tsx_parser if path_str.endswith(".tsx") else self._ts_parser

        try:
            tree = parser.parse(content)
        except (ValueError, OSError) as e:
            logger.warning("Parse error in %s: %s", path_str, e)
            return ParsedFile(
                path=path_str,
                language="typescript",
                line_count=line_count,
            )

        root = tree.root_node

        # Check for parse errors
        if root.has_error:
            logger.debug(
                "Syntax errors in %s, partial results may be incomplete",
                path_str,
            )

        # Extract all information using shared utilities
        imports = extract_es_imports(root, path_str)
        definitions = extract_definitions(root)
        entry_points = extract_entry_points(root, path_str)
        complexity = calculate_complexity(root)

        return ParsedFile(
            path=path_str,
            language="typescript",
            imports=imports,
            definitions=definitions,
            entry_points=entry_points,
            complexity=complexity,
            line_count=line_count,
        )

    def resolve_import(
        self,
        importing_file: str,
        import_target: str,
        repo_files: set[str],
    ) -> str | None:
        """Resolve a TypeScript import to a file path in the repo.

        Handles:
        - Relative imports (.foo, ../bar)
        - Extension-less imports (tries .ts, .tsx, .js, .jsx)
        - Index files (tries index.ts, index.tsx, etc.)

        Bare imports (no . prefix) are treated as external packages.

        Args:
            importing_file: Path of the file containing the import.
            import_target: The raw import string (e.g., "./utils", "../helpers").
            repo_files: Set of all file paths in the repository.

        Returns:
            Resolved file path relative to repo root, or None for external imports.
        """

        return resolve_js_ts_import(
            importing_file, import_target, repo_files, self.resolution_extensions()
        )
