"""In-memory mock implementations for testing downstream services."""

from __future__ import annotations

import threading
from typing import Optional

from neonlink.record import Record


class MockProducer:
    """In-memory producer for testing.

    Records are stored in ``records`` for assertion.
    Inject errors per-topic via ``errors``.
    """

    def __init__(self) -> None:
        self.records: list[Record] = []
        self.errors: dict[str, Exception] = {}
        self._lock = threading.Lock()

    def publish(
        self,
        topic: str,
        key: Optional[bytes],
        value: Optional[bytes],
        headers: Optional[dict[str, str | bytes]] = None,
    ) -> None:
        with self._lock:
            if topic in self.errors:
                raise self.errors[topic]
            self.records.append(Record(
                topic=topic,
                key=key,
                value=value,
                headers=dict(headers) if headers else {},
            ))

    def publish_record(self, record: Record) -> None:
        self.publish(record.topic, record.key, record.value, record.headers)

    def publish_batch(self, records: list[Record]) -> None:
        for rec in records:
            self.publish_record(rec)

    def close(self) -> None:
        pass

    def reset(self) -> None:
        with self._lock:
            self.records.clear()
            self.errors.clear()


class MockConsumer:
    """Delivers pre-loaded records to the handler when subscribe is called."""

    def __init__(self, records: list[Record]) -> None:
        self.records = records

    def subscribe(self, handler) -> None:
        for rec in self.records:
            handler.handle_message(rec)

    def stop(self) -> None:
        pass

    def close(self) -> None:
        pass
