"""Protocol definitions for client mixin composition."""

from __future__ import annotations

import queue
import threading
from collections.abc import Iterable, Sequence
from typing import TYPE_CHECKING, Protocol

if TYPE_CHECKING:
    import numpy as np
    from numpy.typing import NDArray

    from noteflow.grpc._client_mixins.converters import ProtoAnnotation, ProtoMeeting, ProtoSegment
    from noteflow.grpc._types import ConnectionCallback, TranscriptCallback, TranscriptSegment


class ProtoListAnnotationsResponse(Protocol):
    """Protocol for list annotations response payload."""

    annotations: Sequence["ProtoAnnotation"]


class ProtoDeleteAnnotationResponse(Protocol):
    """Protocol for delete annotation response payload."""

    success: bool


class ProtoListMeetingsResponse(Protocol):
    """Protocol for list meetings response payload."""

    meetings: Sequence["ProtoMeeting"]


class ProtoExportTranscriptResponse(Protocol):
    """Protocol for export transcript response payload."""

    content: str
    format_name: str
    file_extension: str


class ProtoDiarizationJobStatus(Protocol):
    """Protocol for diarization job status response payload."""

    job_id: str
    status: int
    segments_updated: int
    speaker_ids: Sequence[str]
    error_message: str


class ProtoRenameSpeakerResponse(Protocol):
    """Protocol for rename speaker response payload."""

    segments_updated: int
    success: bool


class ProtoTranscriptUpdate(Protocol):
    """Protocol for transcript update stream responses."""

    update_type: int
    segment: "ProtoSegment"
    partial_text: str


class ProtoServerInfoResponse(Protocol):
    """Protocol for server info response payload."""

    version: str
    asr_model: str
    asr_ready: bool
    uptime_seconds: float
    active_meetings: int
    diarization_enabled: bool
    diarization_ready: bool


class NoteFlowServiceStubProtocol(Protocol):
    """Protocol for the gRPC service stub used by the client mixins."""

    def AddAnnotation(self, request: object) -> "ProtoAnnotation": ...
    def GetAnnotation(self, request: object) -> "ProtoAnnotation": ...
    def ListAnnotations(self, request: object) -> ProtoListAnnotationsResponse: ...
    def UpdateAnnotation(self, request: object) -> "ProtoAnnotation": ...
    def DeleteAnnotation(self, request: object) -> ProtoDeleteAnnotationResponse: ...

    def CreateMeeting(self, request: object) -> "ProtoMeeting": ...
    def StopMeeting(self, request: object) -> "ProtoMeeting": ...
    def GetMeeting(self, request: object) -> "ProtoMeeting": ...
    def ListMeetings(self, request: object) -> ProtoListMeetingsResponse: ...

    def ExportTranscript(self, request: object) -> ProtoExportTranscriptResponse: ...

    def RefineSpeakerDiarization(self, request: object) -> ProtoDiarizationJobStatus: ...
    def GetDiarizationJobStatus(self, request: object) -> ProtoDiarizationJobStatus: ...
    def RenameSpeaker(self, request: object) -> ProtoRenameSpeakerResponse: ...

    def StreamTranscription(self, request_iterator: Iterable[object]) -> Iterable[ProtoTranscriptUpdate]: ...

    def GetServerInfo(self, request: object) -> ProtoServerInfoResponse: ...


class ClientHost(Protocol):
    """Protocol that client mixins require from the host class."""

    # Streaming state
    stream_thread: threading.Thread | None
    audio_queue: queue.Queue[tuple[str, NDArray[np.float32], float]]
    stop_streaming_event: threading.Event
    current_meeting_id: str | None

    # Callbacks
    on_transcript: TranscriptCallback | None
    on_connection_change: ConnectionCallback | None

    @property
    def stub(self) -> NoteFlowServiceStubProtocol | None:
        """gRPC service stub."""
        ...

    @property
    def connected(self) -> bool:
        """Connection state."""
        ...

    def require_connection(self) -> NoteFlowServiceStubProtocol:
        """Ensure connected and return stub.

        Raises:
            ConnectionError: If not connected.

        Returns:
            The gRPC stub.
        """
        ...

    def stream_worker(self) -> None:
        """Background thread for audio streaming."""
        ...

    def notify_transcript(self, segment: TranscriptSegment) -> None:
        """Notify transcript callback."""
        ...

    def notify_connection(self, connected: bool, message: str) -> None:
        """Notify connection state change."""
        ...

    def stop_streaming(self) -> None:
        """Stop streaming audio."""
        ...
