from __future__ import annotations

from datetime import UTC, datetime
from typing import TYPE_CHECKING

from aiokafka import AIOKafkaProducer
from aiokafka.errors import KafkaError
from loguru import logger

from matyan_backend.config import SETTINGS

if TYPE_CHECKING:
    from matyan_api_models.kafka import ControlEvent


class ControlEventProducer:
    """Async Kafka producer for the ``control-events`` topic."""

    def __init__(self) -> None:
        self._producer: AIOKafkaProducer | None = None

    async def start(self) -> None:
        self._producer = AIOKafkaProducer(
            bootstrap_servers=SETTINGS.kafka_bootstrap_servers,
            value_serializer=lambda v: v.encode() if isinstance(v, str) else v,
            key_serializer=lambda k: k.encode() if isinstance(k, str) else k,
        )
        await self._producer.start()
        logger.info("Kafka control-event producer started ({})", SETTINGS.kafka_bootstrap_servers)

    async def stop(self) -> None:
        if self._producer is not None:
            await self._producer.stop()
            logger.info("Kafka control-event producer stopped")

    async def publish(self, event: ControlEvent) -> None:
        if self._producer is None:
            msg = "Kafka producer not started"
            raise RuntimeError(msg)
        await self._producer.send_and_wait(
            topic=SETTINGS.kafka_control_events_topic,
            value=event.model_dump_json(),
        )


_producer: ControlEventProducer | None = None


def get_producer() -> ControlEventProducer:
    global _producer  # noqa: PLW0603
    if _producer is None:
        _producer = ControlEventProducer()
    return _producer


async def emit_control_event(producer: ControlEventProducer, event_type: str, **payload: object) -> None:
    """Convenience helper used by API endpoints to publish a control event.

    Logs and swallows Kafka failures so that the HTTP response is not
    affected — the FDB write already succeeded and side effects are
    eventually consistent.
    """  # noqa: D401
    from matyan_api_models.kafka import ControlEvent  # noqa: PLC0415

    try:
        await producer.publish(
            ControlEvent(
                type=event_type,
                timestamp=datetime.now(UTC),
                payload=dict(payload),
            ),
        )
    except KafkaError:
        logger.exception("Failed to publish control event", event_type=event_type)
