"""Annotation operations mixin for NoteFlowClient."""

from __future__ import annotations

from typing import TYPE_CHECKING, cast

import grpc

from noteflow.grpc._client_mixins.converters import annotation_type_to_proto, proto_to_annotation_info
from noteflow.grpc._types import AnnotationInfo
from noteflow.grpc.proto import noteflow_pb2
from noteflow.infrastructure.logging import get_logger

if TYPE_CHECKING:
    from noteflow.grpc._client_mixins.protocols import ClientHost

logger = get_logger(__name__)
RpcError = cast(type[Exception], getattr(grpc, "RpcError", Exception))


class AnnotationClientMixin:
    """Mixin providing annotation operations for NoteFlowClient."""

    def add_annotation(
        self: ClientHost,
        meeting_id: str,
        annotation_type: str,
        text: str,
        start_time: float,
        end_time: float,
        segment_ids: list[int] | None = None,
    ) -> AnnotationInfo | None:
        """Add an annotation to a meeting.

        Args:
            meeting_id: Meeting ID.
            annotation_type: Type of annotation (action_item, decision, note).
            text: Annotation text.
            start_time: Start time in seconds.
            end_time: End time in seconds.
            segment_ids: Optional list of linked segment IDs.

        Returns:
            AnnotationInfo or None if request fails.
        """
        if not self.stub:
            return None

        try:
            proto_type = annotation_type_to_proto(annotation_type)
            request = noteflow_pb2.AddAnnotationRequest(
                meeting_id=meeting_id,
                annotation_type=proto_type,
                text=text,
                start_time=start_time,
                end_time=end_time,
                segment_ids=segment_ids or [],
            )
            response = self.stub.AddAnnotation(request)
            return proto_to_annotation_info(response)
        except RpcError as e:
            logger.error("Failed to add annotation: %s", e)
            return None

    def get_annotation(self: ClientHost, annotation_id: str) -> AnnotationInfo | None:
        """Get an annotation by ID.

        Args:
            annotation_id: Annotation ID.

        Returns:
            AnnotationInfo or None if not found.
        """
        if not self.stub:
            return None

        try:
            request = noteflow_pb2.GetAnnotationRequest(annotation_id=annotation_id)
            response = self.stub.GetAnnotation(request)
            return proto_to_annotation_info(response)
        except RpcError as e:
            logger.error("Failed to get annotation: %s", e)
            return None

    def list_annotations(
        self: ClientHost,
        meeting_id: str,
        start_time: float = 0,
        end_time: float = 0,
    ) -> list[AnnotationInfo]:
        """List annotations for a meeting.

        Args:
            meeting_id: Meeting ID.
            start_time: Optional start time filter.
            end_time: Optional end time filter.

        Returns:
            List of AnnotationInfo.
        """
        if not self.stub:
            return []

        try:
            request = noteflow_pb2.ListAnnotationsRequest(
                meeting_id=meeting_id,
                start_time=start_time,
                end_time=end_time,
            )
            response = self.stub.ListAnnotations(request)
            annotations = response.annotations
            return [proto_to_annotation_info(a) for a in annotations]
        except grpc.RpcError as e:
            logger.error("Failed to list annotations: %s", e)
            return []

    def update_annotation(
        self: ClientHost,
        annotation_id: str,
        annotation_type: str | None = None,
        text: str | None = None,
        start_time: float | None = None,
        end_time: float | None = None,
        segment_ids: list[int] | None = None,
    ) -> AnnotationInfo | None:
        """Update an existing annotation.

        Args:
            annotation_id: Annotation ID.
            annotation_type: Optional new type.
            text: Optional new text.
            start_time: Optional new start time.
            end_time: Optional new end time.
            segment_ids: Optional new segment IDs.

        Returns:
            Updated AnnotationInfo or None if request fails.
        """
        if not self.stub:
            return None

        try:
            proto_type = (
                annotation_type_to_proto(annotation_type)
                if annotation_type
                else noteflow_pb2.ANNOTATION_TYPE_UNSPECIFIED
            )
            request = noteflow_pb2.UpdateAnnotationRequest(
                annotation_id=annotation_id,
                annotation_type=proto_type,
                text=text or "",
                start_time=start_time or 0,
                end_time=end_time or 0,
                segment_ids=segment_ids or [],
            )
            response = self.stub.UpdateAnnotation(request)
            return proto_to_annotation_info(response)
        except grpc.RpcError as e:
            logger.error("Failed to update annotation: %s", e)
            return None

    def delete_annotation(self: ClientHost, annotation_id: str) -> bool:
        """Delete an annotation.

        Args:
            annotation_id: Annotation ID.

        Returns:
            True if deleted successfully.
        """
        if not self.stub:
            return False

        try:
            request = noteflow_pb2.DeleteAnnotationRequest(annotation_id=annotation_id)
            response = self.stub.DeleteAnnotation(request)
            return response.success
        except grpc.RpcError as e:
            logger.error("Failed to delete annotation: %s", e)
            return False
