"""
Abstract interface for context retrieval backends.

Each engine retrieves relevant code context for a given ticket instruction,
but uses a different strategy (Clew graph+vector vs standard vector-only).
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol, runtime_checkable


@dataclass
class ContextResult:
    """Result from a context engine query."""

    context: str  # Formatted context string to pass to the coding LLM
    token_count: int  # Approximate token count of the context
    sources: list[str]  # File paths / chunk IDs that contributed


@runtime_checkable
class ContextEngine(Protocol):
    """
    Protocol for swappable context retrieval backends.

    Implementations:
    - ClewContextEngine: Graph + Vector hybrid (the system under test)
    - StandardRAGEngine: Vector-only top-K retrieval (the control)
    """

    async def query(self, instruction: str) -> ContextResult:
        """
        Retrieve code context relevant to a ticket instruction.

        Args:
            instruction: The ticket's task description.

        Returns:
            ContextResult with the formatted context and metadata.
        """
        ...

    async def close(self) -> None:
        """Clean up resources (HTTP clients, etc.)."""
        ...


def estimate_tokens(text: str) -> int:
    """Rough token estimate: ~4 chars per token for code."""
    # This is a heuristic shared across engines for consistency.
    # Real counting would use tiktoken, but this is sufficient for relative comparison.
    return len(text) // 4
