"""Kafka backend for logging to Kafka using klient (glean-kafka)."""

import asyncio
from dataclasses import dataclass
from typing import Any

from ..core.backend import BackendConfig, LoggingBackend, LogRecord
from ..formatters import JSONFormatter, LogFormatter

try:
    from klient.producer import KafkaProducer, ProducerConfig
    KAFKA_AVAILABLE = True
except ImportError:
    KAFKA_AVAILABLE = False
    KafkaProducer = None
    ProducerConfig = None


@dataclass
class KafkaBackendConfig(BackendConfig):
    """Configuration for Kafka backend."""

    enabled: bool = True
    timeout: float = 10.0
    retry_attempts: int = 3
    retry_delay: float = 1.0
    bootstrap_servers: str = "localhost:9092"
    topic: str = "unified-logs"
    batch_size: int = 100
    compression_type: str = "gzip"
    acks: str = "1"


class KafkaBackend(LoggingBackend):
    """Backend that sends logs to Kafka using klient (glean-kafka)."""

    def __init__(
        self,
        name: str = "kafka",
        config: KafkaBackendConfig | None = None,
        formatter: LogFormatter | None = None,
        **kwargs: Any
    ) -> None:
        """Initialize Kafka backend.
        
        Args:
            name: Backend name
            config: Backend configuration
            formatter: Log formatter to use (defaults to JSON)
            **kwargs: Additional configuration
        """
        self.config = config or KafkaBackendConfig()
        super().__init__(name, self.config, **kwargs)

        self.formatter = formatter or JSONFormatter()
        self._producer: KafkaProducer | None = None

    async def connect(self) -> bool:
        """Connect to Kafka cluster."""
        if not KAFKA_AVAILABLE:
            raise ImportError(
                "Kafka backend requires 'klient' package (glean-kafka). "
                "Install from: https://github.com/your-org/glean-kafka"
            )

        try:
            # Create producer configuration
            # Note: confluent-kafka requires acks="all" when idempotence is enabled
            # Disable idempotence to allow flexible acks configuration
            producer_config = ProducerConfig(
                bootstrap_servers=self.config.bootstrap_servers,
                compression_type=self.config.compression_type,
                acks=self.config.acks,
                enable_idempotence=False  # Allow custom acks values
            )

            # Create producer (klient is sync-first with async helpers)
            self._producer = KafkaProducer(producer_config)
            self._connected = True
            return True

        except Exception as e:
            self._producer = None
            self._connected = False
            raise ConnectionError(f"Failed to connect to Kafka: {e}") from e

    async def disconnect(self) -> bool:
        """Disconnect from Kafka."""
        if self._producer:
            try:
                # Flush any pending messages before closing
                self._producer.flush()
                self._producer.close()
                self._producer = None
                self._connected = False
                return True
            except Exception:
                # Ignore errors during disconnect
                self._producer = None
                self._connected = False
                return False
        self._connected = False
        return True

    async def send_log(self, record: LogRecord) -> bool:
        """Send log record to Kafka.
        
        Args:
            record: The log record to send
            
        Returns:
            True if successfully sent, False otherwise
        """
        if not self._producer:
            return False

        try:
            # Format record as string for Kafka
            message = self.formatter.format(record)

            # Create key from logger name and timestamp for partitioning
            key = f"{record.logger_name}_{record.timestamp.strftime('%Y%m%d%H')}"

            # Send using klient's async produce method
            # Note: aproduce returns None and raises exception on failure
            await self._producer.aproduce(
                topic=self.config.topic,
                value=message.encode('utf-8'),
                key=key.encode('utf-8'),
                flush=False  # Batch for performance
            )

            return True

        except Exception as e:
            import logging
            logging.getLogger(__name__).error(
                f"Failed to send log to Kafka: {e}"
            )
            return False

    async def send_logs_batch(self, records: list[LogRecord]) -> list[bool]:
        """Send multiple log records as a batch to Kafka.
        
        Args:
            records: List of log records to send
            
        Returns:
            List of success/failure status for each record
        """
        if not self._producer or not records:
            return [False] * len(records)

        try:
            # Send records in parallel using klient's async produce
            tasks = []
            for record in records:
                message = self.formatter.format(record)
                key = f"{record.logger_name}_{record.timestamp.strftime('%Y%m%d%H')}"
                task = self._producer.aproduce(
                    topic=self.config.topic,
                    value=message.encode('utf-8'),
                    key=key.encode('utf-8'),
                    flush=False
                )
                tasks.append(task)

            # Wait for all sends to complete (aproduce returns None or raises)
            results = await asyncio.gather(*tasks, return_exceptions=True)
            # If result is None, it succeeded; if Exception, it failed
            return [not isinstance(r, Exception) for r in results]

        except Exception:
            return [False] * len(records)

    async def health_check(self) -> bool:
        """Check Kafka cluster connectivity.
        
        Returns:
            True if cluster is healthy, False otherwise
        """
        if not self._producer:
            return False

        try:
            # klient producer is connected if it was created successfully
            # We could test by sending a small message, but that's intrusive
            # Just return connection state
            return self._connected

        except Exception:
            return False
