"""workspace_symbols API implementation.

This module provides the workspace_symbols() function for searching
symbols across the entire workspace with prefix matching.
"""

from __future__ import annotations

import fnmatch
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 SymbolInfo
from .utils import resolve_project

logger = logging.getLogger(__name__)


def workspace_symbols(
    project_root: str,
    query: str,
    kind_filter: Optional[List[str]] = None,
    file_pattern: Optional[str] = None,
    limit: int = 50
) -> List[SymbolInfo]:
    """Search for symbols across the entire workspace.

    Uses prefix matching for efficient searching.

    Args:
        project_root: Project root directory (for index location)
        query: Search query (prefix match)
        kind_filter: Optional list of symbol kinds to include
                    (e.g., ["class", "function"])
        file_pattern: Optional glob pattern to filter by file path
                     (e.g., "*.py", "src/**/*.ts")
        limit: Maximum number of results to return

    Returns:
        List of SymbolInfo sorted by score

    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)

    # Search with prefix matching
    # If kind_filter has multiple kinds, we need to search for each
    all_results: List[Symbol] = []

    if kind_filter and len(kind_filter) > 0:
        # Search for each kind separately
        for kind in kind_filter:
            results = global_index.search(
                name=query,
                kind=kind,
                limit=limit,
                prefix_mode=True
            )
            all_results.extend(results)
    else:
        # Search without kind filter
        all_results = global_index.search(
            name=query,
            kind=None,
            limit=limit,
            prefix_mode=True
        )

    logger.debug(f"Found {len(all_results)} symbols matching '{query}'")

    # Apply file pattern filter if specified
    if file_pattern:
        all_results = [
            sym for sym in all_results
            if sym.file and fnmatch.fnmatch(sym.file, file_pattern)
        ]
        logger.debug(f"After file filter '{file_pattern}': {len(all_results)} symbols")

    # Convert to SymbolInfo and sort by relevance
    symbols = [
        SymbolInfo(
            name=sym.name,
            kind=sym.kind,
            file_path=sym.file or "",
            line=sym.range[0] if sym.range else 1,
            container=None,  # Could extract from parent
            score=_calculate_score(sym.name, query)
        )
        for sym in all_results
    ]

    # Sort by score (exact matches first)
    symbols.sort(key=lambda s: s.score, reverse=True)

    return symbols[:limit]


def _calculate_score(symbol_name: str, query: str) -> float:
    """Calculate relevance score for a symbol match.

    Scoring:
    - Exact match: 1.0
    - Prefix match: 0.8 + 0.2 * (query_len / symbol_len)
    - Case-insensitive match: 0.6

    Args:
        symbol_name: The matched symbol name
        query: The search query

    Returns:
        Score between 0.0 and 1.0
    """
    if symbol_name == query:
        return 1.0

    if symbol_name.lower() == query.lower():
        return 0.9

    if symbol_name.startswith(query):
        ratio = len(query) / len(symbol_name)
        return 0.8 + 0.2 * ratio

    if symbol_name.lower().startswith(query.lower()):
        ratio = len(query) / len(symbol_name)
        return 0.6 + 0.2 * ratio

    return 0.5
