"""Export mixin for gRPC service."""

from __future__ import annotations

import base64
from typing import TYPE_CHECKING, Protocol

from noteflow.application.services.export_service import (
    ExportFormat,
    ExportRepositoryProvider,
    ExportService,
)
from noteflow.config.constants import EXPORT_EXT_HTML, EXPORT_EXT_PDF, EXPORT_FORMAT_HTML
from noteflow.infrastructure.logging import get_logger

from ..proto import noteflow_pb2
from ._types import GrpcContext
from .converters import parse_meeting_id_or_abort, proto_to_export_format
from .errors import ENTITY_MEETING, abort_not_found

if TYPE_CHECKING:
    from noteflow.domain.ports.unit_of_work import UnitOfWork

    from ._types import GrpcContext

logger = get_logger(__name__)

# Format metadata lookup
_FORMAT_METADATA: dict[ExportFormat, tuple[str, str]] = {
    ExportFormat.MARKDOWN: ("Markdown", ".md"),
    ExportFormat.HTML: (EXPORT_FORMAT_HTML, EXPORT_EXT_HTML),
    ExportFormat.PDF: ("PDF", EXPORT_EXT_PDF),
}


class ExportServicer(Protocol):
    """Protocol for hosts that support export operations."""

    def create_repository_provider(self) -> ExportRepositoryProvider | UnitOfWork: ...


class ExportMixin:
    """Mixin providing export functionality.

    Requires host to implement ServicerHost protocol.
    Works with both database and memory backends via RepositoryProvider.
    """

    async def ExportTranscript(
        self: ExportServicer,
        request: noteflow_pb2.ExportTranscriptRequest,
        context: GrpcContext,
    ) -> noteflow_pb2.ExportTranscriptResponse:
        """Export meeting transcript to specified format."""
        # Map proto format to ExportFormat
        fmt = proto_to_export_format(request.format)
        fmt_name, fmt_ext = _FORMAT_METADATA.get(fmt, ("Unknown", ""))

        logger.info(
            "Export requested: meeting_id=%s format=%s",
            request.meeting_id,
            fmt_name,
        )

        # Use unified repository provider - works with both DB and memory
        meeting_id = await parse_meeting_id_or_abort(request.meeting_id, context)

        export_service = ExportService(self.create_repository_provider())
        try:
            result = await export_service.export_transcript(
                meeting_id,
                fmt,
            )

            # Handle bytes vs string output
            # PDF returns bytes which must be base64-encoded for gRPC string transport
            if isinstance(result, bytes):
                content = base64.b64encode(result).decode("ascii")
                content_size = len(result)
            else:
                content = result
                content_size = len(content)

            logger.info(
                "Export completed: meeting_id=%s format=%s bytes=%d",
                request.meeting_id,
                fmt_name,
                content_size,
            )

            return noteflow_pb2.ExportTranscriptResponse(
                content=content,
                format_name=fmt_name,
                file_extension=fmt_ext,
            )
        except ValueError as exc:
            logger.error(
                "Export failed: meeting_id=%s format=%s error=%s",
                request.meeting_id,
                fmt_name,
                str(exc),
            )
            await abort_not_found(context, ENTITY_MEETING, request.meeting_id)
