"""Search operations: BM25, vector, and hybrid."""

import json
import time

from rich.console import Console
from rich.markup import escape

from .config import get_backend_config
from .core.backends import get_backend, SearchResult
from .embedder import Embedder

console = Console()

# Shared lazy embedder instance
_embedder: Embedder | None = None


def _get_embedder() -> Embedder:
    global _embedder
    if _embedder is None:
        _embedder = Embedder()
    return _embedder


def _get_backend():
    backend_type, backend_config = get_backend_config()
    return get_backend(backend_type, **backend_config)


def bm25_search(
    query: str,
    limit: int = 5,
    collection: str | None = None,
) -> SearchResult:
    """Pure BM25 full-text search."""
    backend = _get_backend()
    t0 = time.perf_counter()
    result = backend.bm25_search(collection or 'mykb', query, limit=limit)
    elapsed = time.perf_counter() - t0
    console.print(f'[dim]Backend BM25 query [bold]({elapsed:.3f}s)[/bold][/dim]')
    return result


def vector_search(
    query: str,
    limit: int = 5,
    collection: str | None = None,
) -> SearchResult:
    """Pure vector semantic search (semanticRatio=1.0)."""
    t_total = time.perf_counter()
    embedder = _get_embedder()
    query_vec = embedder.encode_query(query)

    backend = _get_backend()
    t0 = time.perf_counter()
    result = backend.vector_search(collection or 'mykb', query_vec, limit=limit)
    elapsed_ms = time.perf_counter() - t0
    elapsed_total = time.perf_counter() - t_total
    console.print(
        f'[dim]Backend vector query [bold]({elapsed_ms:.3f}s)[/bold] | total [bold]({elapsed_total:.2f}s)[/bold][/dim]'
    )
    return result


def hybrid_search(
    query: str,
    limit: int = 5,
    collection: str | None = None,
    semantic_ratio: float = 0.5,
) -> SearchResult:
    """Hybrid search combining BM25 and vector search."""
    t_total = time.perf_counter()
    embedder = _get_embedder()
    query_vec = embedder.encode_query(query)

    backend = _get_backend()
    t0 = time.perf_counter()
    result = backend.hybrid_search(
        collection or 'mykb',
        query,
        query_vec,
        limit=limit,
        semantic_ratio=semantic_ratio,
    )
    elapsed_ms = time.perf_counter() - t0
    elapsed_total = time.perf_counter() - t_total
    console.print(
        f'[dim]Backend hybrid query [bold]({elapsed_ms:.3f}s)[/bold] | total [bold]({elapsed_total:.2f}s)[/bold][/dim]'
    )
    return result


def format_results_json(results: SearchResult) -> str:
    """Format search results as JSON."""
    output = []
    for hit in results.hits:
        doc = hit.document
        output.append(
            {
                'title': doc.get('title', ''),
                'source_path': doc.get('source_path', ''),
                'source_uri': doc.get('source_uri', ''),
                'collection': doc.get('collection', ''),
                'chunk_index': doc.get('chunk_index', 0),
                'score': hit.score,
                'content': doc.get('content', ''),
                'tags': doc.get('tags', []),
            }
        )
    return json.dumps(output, indent=2, ensure_ascii=False)


def format_results_rich(results: SearchResult, show_full: bool = False):
    """Format search results with rich terminal output."""
    if not results.hits:
        console.print('[yellow]No results found.[/yellow]')
        return

    console.print(f'\n[bold]{len(results.hits)} result(s)[/bold] (query time: {results.processing_time_ms}ms)\n')

    for i, hit in enumerate(results.hits, 1):
        doc = hit.document
        score = hit.score
        title = doc.get('title', 'Untitled')
        source = doc.get('source_path', '')
        collection = doc.get('collection', '')
        chunk_idx = doc.get('chunk_index', 0)
        tags = doc.get('tags', [])

        # Header line
        console.print(f'[bold cyan]{i}.[/bold cyan] [bold]{escape(title)}[/bold]  [dim]score={score:.4f}[/dim]')
        console.print(f'   [dim]{escape(collection)}:{escape(source)} (chunk {chunk_idx})[/dim]')

        if tags:
            tag_str = ' '.join(f'[magenta]#{t}[/magenta]' for t in tags[:5])
            console.print(f'   {tag_str}')

        # Content snippet
        if show_full:
            content = doc.get('content', '')
        else:
            # Use highlighted content if available, or truncate
            formatted = doc.get('_formatted', {})
            content = formatted.get('content', doc.get('content', ''))
            # Truncate to ~200 chars
            if len(content) > 200:
                content = content[:200] + '...'

        # Replace highlight markers with rich markup
        content = content.replace('<<', '[bold yellow]').replace('>>', '[/bold yellow]')
        console.print(f'   {content}')
        console.print()
