"""find_definition API implementation.

This module provides the find_definition() function for looking up
symbol definitions with a 3-stage fallback strategy.
"""

from __future__ import annotations

import logging
from pathlib import Path
from typing import List, Optional

from ..entities import Symbol
from ..storage.global_index import GlobalSymbolIndex
from ..storage.registry import RegistryStore
from ..errors import IndexNotFoundError
from .models import DefinitionResult
from .utils import resolve_project, rank_by_proximity

logger = logging.getLogger(__name__)


def find_definition(
    project_root: str,
    symbol_name: str,
    symbol_kind: Optional[str] = None,
    file_context: Optional[str] = None,
    limit: int = 10
) -> List[DefinitionResult]:
    """Find definition locations for a symbol.

    Uses a 3-stage fallback strategy:
        1. Exact match with kind filter
        2. Exact match without kind filter
        3. Prefix match

    Args:
        project_root: Project root directory (for index location)
        symbol_name: Name of the symbol to find
        symbol_kind: Optional symbol kind filter (class, function, etc.)
        file_context: Optional file path for proximity ranking
        limit: Maximum number of results to return

    Returns:
        List of DefinitionResult sorted by proximity if file_context provided

    Raises:
        IndexNotFoundError: If project is not indexed
    """
    project_path = resolve_project(project_root)

    # Get project info from registry
    registry = RegistryStore()
    project_info = registry.get_project(project_path)
    if project_info is None:
        raise IndexNotFoundError(f"Project not indexed: {project_path}")

    # Open global symbol index
    index_db = project_info.index_root / "_global_symbols.db"
    if not index_db.exists():
        raise IndexNotFoundError(f"Global symbol index not found: {index_db}")

    global_index = GlobalSymbolIndex(str(index_db), project_info.id)

    # Stage 1: Exact match with kind filter
    results = _search_with_kind(global_index, symbol_name, symbol_kind, limit)
    if results:
        logger.debug(f"Stage 1 (exact+kind): Found {len(results)} results for {symbol_name}")
        return _rank_and_convert(results, file_context)

    # Stage 2: Exact match without kind (if kind was specified)
    if symbol_kind:
        results = _search_with_kind(global_index, symbol_name, None, limit)
        if results:
            logger.debug(f"Stage 2 (exact): Found {len(results)} results for {symbol_name}")
            return _rank_and_convert(results, file_context)

    # Stage 3: Prefix match
    results = global_index.search(
        name=symbol_name,
        kind=None,
        limit=limit,
        prefix_mode=True
    )
    if results:
        logger.debug(f"Stage 3 (prefix): Found {len(results)} results for {symbol_name}")
        return _rank_and_convert(results, file_context)

    logger.debug(f"No definitions found for {symbol_name}")
    return []


def _search_with_kind(
    global_index: GlobalSymbolIndex,
    symbol_name: str,
    symbol_kind: Optional[str],
    limit: int
) -> List[Symbol]:
    """Search for symbols with optional kind filter."""
    return global_index.search(
        name=symbol_name,
        kind=symbol_kind,
        limit=limit,
        prefix_mode=False
    )


def _rank_and_convert(
    symbols: List[Symbol],
    file_context: Optional[str]
) -> List[DefinitionResult]:
    """Convert symbols to DefinitionResult and rank by proximity."""
    results = [
        DefinitionResult(
            name=sym.name,
            kind=sym.kind,
            file_path=sym.file or "",
            line=sym.range[0] if sym.range else 1,
            end_line=sym.range[1] if sym.range else 1,
            signature=None,  # Could extract from file if needed
            container=None,  # Could extract from parent symbol
            score=1.0
        )
        for sym in symbols
    ]
    return rank_by_proximity(results, file_context)
