"""Summarization provider port protocols."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import TYPE_CHECKING, Final, Protocol

if TYPE_CHECKING:
    from collections.abc import Sequence

    from noteflow.domain.entities import Segment, Summary
    from noteflow.domain.value_objects import MeetingId

# =============================================================================
# Summary Generation Defaults (single source of truth)
# =============================================================================

DEFAULT_MAX_KEY_POINTS: Final[int] = 5
"""Default maximum number of key points in a summary."""

DEFAULT_MAX_ACTION_ITEMS: Final[int] = 10
"""Default maximum number of action items in a summary."""


@dataclass(frozen=True)
class SummarizationRequest:
    """Request for meeting summarization.

    Contains the meeting context needed for summary generation.
    """

    meeting_id: MeetingId
    segments: Sequence[Segment]
    max_key_points: int = DEFAULT_MAX_KEY_POINTS
    max_action_items: int = DEFAULT_MAX_ACTION_ITEMS
    style_prompt: str | None = None

    @property
    def transcript_text(self) -> str:
        """Concatenate all segment text into a single transcript."""
        segments = self.segments
        return " ".join(seg.text for seg in segments)

    @property
    def segment_count(self) -> int:
        """Number of segments in the request."""
        return len(self.segments)

    @property
    def total_duration(self) -> float:
        """Total duration of all segments in seconds."""
        if not self.segments:
            return 0.0
        return self.segments[-1].end_time - self.segments[0].start_time


@dataclass(frozen=True)
class SummarizationResult:
    """Result from summarization provider.

    Contains the generated summary along with metadata.
    """

    summary: Summary
    model_name: str
    provider_name: str
    tokens_used: int | None = None
    latency_ms: float = 0.0

    @property
    def is_success(self) -> bool:
        """Check if summarization succeeded with meaningful content.

        Returns:
            True if executive_summary has non-whitespace content.
        """
        summary_text = self.summary.executive_summary
        return bool(summary_text and summary_text.strip())


@dataclass(frozen=True)
class CitationVerificationResult:
    """Result of citation verification.

    Identifies which citations are valid and which are invalid.
    """

    is_valid: bool
    invalid_key_point_indices: tuple[int, ...] = field(default_factory=tuple)
    invalid_action_item_indices: tuple[int, ...] = field(default_factory=tuple)
    missing_segment_ids: tuple[int, ...] = field(default_factory=tuple)

    @property
    def invalid_count(self) -> int:
        """Total number of invalid citations."""
        return len(self.invalid_key_point_indices) + len(self.invalid_action_item_indices)


class SummarizerProvider(Protocol):
    """Protocol for LLM summarization providers.

    Implementations must provide async summarization with evidence linking.
    """

    @property
    def provider_name(self) -> str:
        """Provider identifier (e.g., 'mock', 'ollama', 'openai')."""
        ...

    @property
    def is_available(self) -> bool:
        """Check if provider is configured and available."""
        ...

    @property
    def requires_cloud_consent(self) -> bool:
        """Return True if data is sent to external services.

        Cloud providers must return True to ensure explicit user consent.
        """
        ...

    async def summarize(self, request: SummarizationRequest) -> SummarizationResult:
        """Generate evidence-linked summary from transcript segments.

        Args:
            request: Summarization request with segments and constraints.

        Returns:
            SummarizationResult with generated summary and metadata.

        Raises:
            SummarizationError: If summarization fails.
        """
        ...


class CitationVerifier(Protocol):
    """Protocol for verifying evidence citations.

    Validates that segment_ids in summaries reference actual segments.
    """

    def verify_citations(
        self,
        summary: Summary,
        segments: Sequence[Segment],
    ) -> CitationVerificationResult:
        """Verify all segment_ids exist in the transcript.

        Args:
            summary: Summary with key points and action items to verify.
            segments: Available transcript segments.

        Returns:
            CitationVerificationResult with validation status and details.
        """
        ...

    def filter_invalid_citations(
        self,
        summary: Summary,
        segments: Sequence[Segment],
    ) -> Summary:
        """Return a copy of the summary with invalid citations removed.

        Invalid segment_ids are removed from key points and action items.
        Items with no remaining citations keep empty segment_ids lists.

        Args:
            summary: Summary to filter.
            segments: Available transcript segments.

        Returns:
            New Summary with invalid citations removed.
        """
        ...


class SummarizationError(Exception):
    """Base exception for summarization errors."""

    pass


class ProviderUnavailableError(SummarizationError):
    """Provider is not available or not configured."""

    pass


class SummarizationTimeoutError(SummarizationError):
    """Summarization operation timed out."""

    pass


class InvalidResponseError(SummarizationError):
    """Provider returned an invalid or unparseable response."""

    pass
