"""Abstract base class and shared types for the signal search API."""

from __future__ import annotations

from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from typing import Any

from .query import Operator, Query


@dataclass
class SearchOptions:
    exact: bool = False
    substring: bool = False
    operator: Operator = Operator.AND
    source_filter: str | None = None
    file_path_filter: str | None = None
    filters: dict[str, str] = field(default_factory=dict)


@dataclass
class StatusResult:
    total: int
    last_indexed: str | None = None


class SearchAPI(ABC):
    @abstractmethod
    def connect(self) -> None: ...

    @abstractmethod
    def close(self) -> None: ...

    @abstractmethod
    def clear(self) -> None: ...

    @abstractmethod
    def index_signals(self, signals: list[dict[str, Any]]) -> int: ...

    @abstractmethod
    def index_yaml_data(self, file_path: str, workspace_path: str, raw: str) -> int: ...

    @abstractmethod
    def search(
        self,
        query: Query,
        limit: int = 50,
        opts: SearchOptions | None = None,
    ) -> list[dict[str, Any]]: ...

    @abstractmethod
    def search_slim(
        self,
        query: Query,
        opts: SearchOptions | None = None,
    ) -> list[str]:
        """Return matching signals as ``"namespace:name"`` or ``"channel:name"`` strings."""

    @abstractmethod
    def suggest(
        self,
        query: Query,
        selected: list[Query] | None = None,
        limit: int = 20,
        opts: SearchOptions | None = None,
    ) -> tuple[list[dict[str, str]], int]: ...

    @abstractmethod
    def status(  # noqa: PLR0913
        self,
        source_filter: str | None = None,
        file_path_filter: str | None = None,
        filters: dict[str, str] | None = None,
        query: Query | None = None,
        exact: bool = False,
        substring: bool = False,
        operator: Operator = Operator.AND,
    ) -> StatusResult: ...
