"""Webhook application service for event notifications."""

from __future__ import annotations

from typing import TYPE_CHECKING

from noteflow.config.constants import DEFAULT_MEETING_TITLE
from noteflow.domain.utils.time import utc_now
from noteflow.domain.webhooks import (
    MeetingCompletedPayload,
    RecordingPayload,
    SummaryGeneratedPayload,
    WebhookConfig,
    WebhookDelivery,
    WebhookEventType,
    WebhookPayloadDict,
    payload_to_dict,
)
from noteflow.infrastructure.logging import get_logger
from noteflow.infrastructure.webhooks import WebhookExecutor

if TYPE_CHECKING:
    from noteflow.domain.entities.meeting import Meeting

_logger = get_logger(__name__)


class WebhookService:
    """Orchestrate webhook delivery for meeting events.

    Manages webhook configurations and coordinates delivery
    across all registered webhooks for each event type.
    """

    def __init__(
        self,
        executor: WebhookExecutor | None = None,
    ) -> None:
        """Initialize webhook service.

        Args:
            executor: Webhook executor instance (created if not provided).
        """
        self._executor = executor or WebhookExecutor()
        self.configs: list[WebhookConfig] = []

    def register_webhook(self, config: WebhookConfig) -> None:
        """Register a webhook configuration.

        Args:
            config: Webhook configuration to register.
        """
        self.configs.append(config)
        _logger.info(
            "Registered webhook: %s for events: %s",
            config.url,
            [e.value for e in config.events],
        )

    def unregister_webhook(self, webhook_id: str) -> bool:
        """Unregister a webhook by ID.

        Args:
            webhook_id: UUID of webhook to remove.

        Returns:
            True if webhook was found and removed.
        """
        initial_count = len(self.configs)
        self.configs = [c for c in self.configs if str(c.id) != webhook_id]
        removed = len(self.configs) < initial_count
        if removed:
            _logger.info("Unregistered webhook: %s", webhook_id)
        return removed

    async def trigger_meeting_completed(
        self,
        meeting: Meeting,
    ) -> list[WebhookDelivery]:
        """Trigger webhooks for meeting completion.

        Args:
            meeting: Completed meeting entity.

        Returns:
            List of delivery records for all webhook attempts.
        """
        payload = MeetingCompletedPayload(
            event=WebhookEventType.MEETING_COMPLETED.value,
            timestamp=utc_now().isoformat(),
            meeting_id=str(meeting.id),
            title=meeting.title or DEFAULT_MEETING_TITLE,
            duration_seconds=meeting.duration_seconds or 0.0,
            segment_count=len(meeting.segments),
            has_summary=meeting.summary is not None,
        )

        return await self._deliver_to_all(
            WebhookEventType.MEETING_COMPLETED,
            payload_to_dict(payload),
        )

    async def trigger_summary_generated(
        self,
        meeting: Meeting,
    ) -> list[WebhookDelivery]:
        """Trigger webhooks for summary generation.

        Args:
            meeting: Meeting with generated summary.

        Returns:
            List of delivery records for all webhook attempts.
        """
        summary = meeting.summary
        payload = SummaryGeneratedPayload(
            event=WebhookEventType.SUMMARY_GENERATED.value,
            timestamp=utc_now().isoformat(),
            meeting_id=str(meeting.id),
            title=meeting.title or DEFAULT_MEETING_TITLE,
            executive_summary=summary.executive_summary if summary else "",
            key_points_count=len(summary.key_points) if summary else 0,
            action_items_count=len(summary.action_items) if summary else 0,
        )

        return await self._deliver_to_all(
            WebhookEventType.SUMMARY_GENERATED,
            payload_to_dict(payload),
        )

    async def trigger_recording_started(
        self,
        meeting_id: str,
        title: str,
    ) -> list[WebhookDelivery]:
        """Trigger webhooks for recording start.

        Args:
            meeting_id: ID of meeting being recorded.
            title: Meeting title.

        Returns:
            List of delivery records.
        """
        payload = RecordingPayload(
            event=WebhookEventType.RECORDING_STARTED.value,
            timestamp=utc_now().isoformat(),
            meeting_id=meeting_id,
            title=title,
        )

        return await self._deliver_to_all(
            WebhookEventType.RECORDING_STARTED,
            payload_to_dict(payload),
        )

    async def trigger_recording_stopped(
        self,
        meeting_id: str,
        title: str,
        duration_seconds: float,
    ) -> list[WebhookDelivery]:
        """Trigger webhooks for recording stop.

        Args:
            meeting_id: ID of meeting.
            title: Meeting title.
            duration_seconds: Recording duration.

        Returns:
            List of delivery records.
        """
        payload = RecordingPayload(
            event=WebhookEventType.RECORDING_STOPPED.value,
            timestamp=utc_now().isoformat(),
            meeting_id=meeting_id,
            title=title,
            duration_seconds=duration_seconds,
        )

        return await self._deliver_to_all(
            WebhookEventType.RECORDING_STOPPED,
            payload_to_dict(payload),
        )

    async def _deliver_to_all(
        self,
        event_type: WebhookEventType,
        payload: WebhookPayloadDict,
    ) -> list[WebhookDelivery]:
        """Deliver event to all registered webhooks.

        Args:
            event_type: Type of event.
            payload: Event payload.

        Returns:
            List of delivery records.
        """
        deliveries: list[WebhookDelivery] = []

        for config in self.configs:
            try:
                delivery = await self._executor.deliver(config, event_type, payload)
                deliveries.append(delivery)

                if delivery.succeeded:
                    _logger.info(
                        "Webhook delivered: %s -> %s (status=%d)",
                        event_type.value,
                        config.url,
                        delivery.status_code,
                    )
                elif delivery.attempt_count > 0:
                    _logger.warning(
                        "Webhook failed: %s -> %s (error=%s)",
                        event_type.value,
                        config.url,
                        delivery.error_message,
                    )
                else:
                    _logger.debug(
                        "Webhook skipped: %s -> %s (reason=%s)",
                        event_type.value,
                        config.url,
                        delivery.error_message,
                    )

            # INTENTIONAL BROAD HANDLER: Fire-and-forget webhook delivery
            # - Webhook failures must never block calling code
            # - All exceptions logged but suppressed
            except Exception:
                _logger.exception("Unexpected error delivering webhook to %s", config.url)

        return deliveries

    async def close(self) -> None:
        """Clean up resources."""
        await self._executor.close()
