"""Repository protocols for background job and preferences entities.

Contains DiarizationJob and Preferences repository protocols.
"""

from __future__ import annotations

from collections.abc import Sequence
from datetime import datetime
from typing import TYPE_CHECKING, Protocol

from noteflow.config.constants import ERR_SERVER_RESTARTED

if TYPE_CHECKING:
    from noteflow.infrastructure.persistence.repositories import (
        DiarizationJob,
        PreferenceWithMetadata,
        StreamingTurn,
    )


class DiarizationJobRepository(Protocol):
    """Repository protocol for DiarizationJob operations.

    Tracks background speaker diarization jobs for crash resilience
    and client visibility.
    """

    async def create(self, job: DiarizationJob) -> DiarizationJob:
        """Persist a new diarization job.

        Args:
            job: DiarizationJob data object.

        Returns:
            Created job.
        """
        ...

    async def get(self, job_id: str) -> DiarizationJob | None:
        """Retrieve a job by ID.

        Args:
            job_id: Job identifier.

        Returns:
            Job if found, None otherwise.
        """
        ...

    async def update_status(
        self,
        job_id: str,
        status: int,
        *,
        segments_updated: int | None = None,
        speaker_ids: list[str] | None = None,
        error_message: str | None = None,
        started_at: datetime | None = None,
    ) -> bool:
        """Update job status and optional fields.

        Args:
            job_id: Job identifier.
            status: New status value.
            segments_updated: Optional segments count.
            speaker_ids: Optional speaker IDs list.
            error_message: Optional error message.
            started_at: Optional job start timestamp.

        Returns:
            True if job was updated, False if not found.
        """
        ...

    async def prune_completed(self, ttl_seconds: float) -> int:
        """Delete completed/failed jobs older than TTL.

        Args:
            ttl_seconds: Time-to-live in seconds.

        Returns:
            Number of jobs deleted.
        """
        ...

    async def add_streaming_turns(
        self,
        meeting_id: str,
        turns: Sequence[StreamingTurn],
    ) -> int:
        """Persist streaming diarization turns for crash resilience.

        Args:
            meeting_id: Meeting identifier.
            turns: Speaker turns to persist.

        Returns:
            Number of turns added.
        """
        ...

    async def get_streaming_turns(self, meeting_id: str) -> list[StreamingTurn]:
        """Retrieve streaming diarization turns for a meeting.

        Args:
            meeting_id: Meeting identifier.

        Returns:
            List of streaming turns.
        """
        ...

    async def clear_streaming_turns(self, meeting_id: str) -> int:
        """Delete streaming diarization turns for a meeting.

        Args:
            meeting_id: Meeting identifier.

        Returns:
            Number of turns deleted.
        """
        ...

    async def mark_running_as_failed(
        self, error_message: str = ERR_SERVER_RESTARTED,
    ) -> int:
        """Mark queued/running jobs as failed.

        Args:
            error_message: Error message to set on failed jobs.

        Returns:
            Number of jobs marked as failed.
        """
        ...

    async def get_active_for_meeting(self, meeting_id: str) -> DiarizationJob | None:
        """Get active (QUEUED or RUNNING) job for meeting.

        Args:
            meeting_id: Meeting identifier.

        Returns:
            Active job if found, None otherwise.
        """
        ...

    async def get_all_active(self) -> list[DiarizationJob]:
        """Get all active (QUEUED or RUNNING) jobs.

        Returns:
            List of active jobs across all meetings.
        """
        ...


class PreferencesRepository(Protocol):
    """Repository protocol for user preferences operations.

    Stores key-value user preferences for persistence across server restarts.
    """

    async def get(self, key: str) -> object | None:
        """Get preference value by key.

        Args:
            key: Preference key.

        Returns:
            Preference value or None if not found.
        """
        ...

    async def get_bool(self, key: str, default: bool = False) -> bool:
        """Get a boolean preference.

        Args:
            key: Preference key.
            default: Default value if not found.

        Returns:
            Boolean preference value.
        """
        ...

    async def set(self, key: str, value: object) -> None:
        """Set preference value.

        Args:
            key: Preference key.
            value: Preference value.
        """
        ...

    async def delete(self, key: str) -> bool:
        """Delete a preference.

        Args:
            key: Preference key.

        Returns:
            True if deleted, False if not found.
        """
        ...

    async def get_all_with_metadata(
        self,
        keys: Sequence[str] | None = None,
    ) -> list[PreferenceWithMetadata]:
        """Get all preferences with metadata (key, value, updated_at).

        Args:
            keys: Optional list of keys to filter by. If None, returns all.

        Returns:
            List of PreferenceWithMetadata objects.
        """
        ...

    async def set_bulk(self, preferences: dict[str, object]) -> None:
        """Set multiple preferences at once.

        Args:
            preferences: Dictionary of key-value pairs.
        """
        ...
