"""Get-or-abort helpers for gRPC service mixins.

Provides functions that fetch entities and abort with NOT_FOUND if missing.
"""

from __future__ import annotations

from typing import TYPE_CHECKING
from uuid import UUID

from ._abort import AbortableContext, abort_not_found

if TYPE_CHECKING:
    from noteflow.application.services.project_service import ProjectService
    from noteflow.application.services.project_service._types import (
        ProjectCrudRepositoryProvider,
    )
    from noteflow.domain.entities.meeting import Meeting, MeetingId
    from noteflow.domain.entities.project import Project
    from noteflow.domain.ports.unit_of_work import UnitOfWork
    from noteflow.domain.webhooks.events import WebhookConfig

# Entity type names for abort_not_found calls
ENTITY_MEETING = "Meeting"
ENTITY_ENTITY = "Entity"
ENTITY_INTEGRATION = "Integration"
ENTITY_PROJECT = "Project"
ENTITY_SYNC_RUN = "SyncRun"
ENTITY_WEBHOOK = "Webhook"


async def get_meeting_or_abort(
    uow: UnitOfWork,
    meeting_id: MeetingId,
    context: AbortableContext,
) -> Meeting:
    """Get meeting by ID, aborting with NOT_FOUND if missing.

    Args:
        uow: Unit of work with meetings repository.
        meeting_id: The meeting ID to look up.
        context: gRPC servicer context for abort.

    Returns:
        The meeting if found.

    Raises:
        grpc.RpcError: NOT_FOUND if meeting doesn't exist.
    """
    meeting = await uow.meetings.get(meeting_id)
    if meeting is None:
        await abort_not_found(context, ENTITY_MEETING, str(meeting_id))
    assert meeting is not None  # Type narrowing: abort never returns
    return meeting


async def get_project_or_abort(
    project_service: ProjectService,
    uow: ProjectCrudRepositoryProvider,
    project_id: UUID,
    context: AbortableContext,
) -> Project:
    """Get project by ID via service, aborting with NOT_FOUND if missing.

    Args:
        project_service: Project service for fetching.
        uow: Unit of work for repository access.
        project_id: The project ID to look up.
        context: gRPC servicer context for abort.

    Returns:
        The project if found.

    Raises:
        grpc.RpcError: NOT_FOUND if project doesn't exist.
    """
    project = await project_service.get_project(uow, project_id)
    if project is None:
        await abort_not_found(context, ENTITY_PROJECT, str(project_id))
    assert project is not None  # Type narrowing: abort never returns
    return project


async def get_webhook_or_abort(
    uow: UnitOfWork,
    webhook_id: UUID,
    context: AbortableContext,
) -> WebhookConfig:
    """Get webhook config by ID, aborting with NOT_FOUND if missing.

    Args:
        uow: Unit of work with webhooks repository.
        webhook_id: The webhook ID to look up.
        context: gRPC servicer context for abort.

    Returns:
        The webhook config if found.

    Raises:
        grpc.RpcError: NOT_FOUND if webhook doesn't exist.
    """
    config = await uow.webhooks.get_by_id(webhook_id)
    if config is None:
        await abort_not_found(context, ENTITY_WEBHOOK, str(webhook_id))
    assert config is not None  # Type narrowing: abort never returns
    return config
