from collections.abc import Iterable
from typing import Any, Protocol

from home_agent.contracts.types import (
    Alert,
    EmbeddingRecord,
    Item,
    LLMResult,
    MemoryRuleCandidate,
    RenderedItemText,
    RetrievalDecisionTrace,
    RetrievalQuery,
    RetrievedMatch,
    UrgencyDecision,
    VectorDocument,
    VectorQuery,
    VectorSearchResult,
)


class TokenStore(Protocol):
    def load(self, name: str) -> dict[str, Any] | None: ...

    def save(self, name: str, payload: dict[str, Any]) -> None: ...


class MailReader(Protocol):
    def list_recent(self) -> Iterable[Item]: ...

    def search(self, query: str) -> Iterable[Item]: ...

    def get_message(self, external_id: str) -> Item | None: ...


class CalendarReader(Protocol):
    def list_upcoming(self) -> Iterable[Item]: ...

    def get_event(self, external_id: str) -> Item | None: ...


class ProviderPlugin(Protocol):
    id: str
    version: str

    def get_mail_reader(self) -> MailReader | None: ...

    def get_calendar_reader(self) -> CalendarReader | None: ...


class LLMRunner(Protocol):
    def classify(
        self, item: Item, retrieved_matches: list[RetrievedMatch] | None = None
    ) -> LLMResult: ...


class Notifier(Protocol):
    def notify(self, alert: Alert) -> None: ...


class MemoryEngine(Protocol):
    def extract_candidates(self, important_items: list[Item]) -> list[MemoryRuleCandidate]: ...

    def apply_active_rules(self, active_rule_keys: set[str], item: Item) -> list[str]: ...


class UrgencyEngine(Protocol):
    def score(self, item: Item) -> UrgencyDecision: ...


class EmbeddingProvider(Protocol):
    @property
    def provider_name(self) -> str: ...

    @property
    def model_name(self) -> str: ...

    def embed_texts(self, texts: list[str]) -> list[list[float]]: ...


class ItemTextRenderer(Protocol):
    def render(self, item: Item) -> RenderedItemText: ...


class RetrievalStore(Protocol):
    def save_item_text(self, rendered: RenderedItemText) -> None: ...

    def get_item_text(self, provider: str, external_id: str) -> RenderedItemText | None: ...

    def save_item_embedding(self, record: EmbeddingRecord) -> None: ...

    def save_retrieval_event(self, trace: RetrievalDecisionTrace) -> None: ...


class Retriever(Protocol):
    def find_similar(self, query: RetrievalQuery) -> list[RetrievedMatch]: ...


class VectorBackend(Protocol):
    @property
    def backend_name(self) -> str: ...

    def upsert_documents(self, documents: list[VectorDocument]) -> None: ...

    def query_similar(self, query: VectorQuery) -> list[VectorSearchResult]: ...

    def healthcheck(self) -> None: ...

    def indexed_count(self) -> int: ...

    def rebuild(self, documents: list[VectorDocument]) -> None: ...

    def has_document(self, key: object) -> bool: ...
