"""
karapace - Karapace offset watcher

Copyright (c) 2023 Aiven Ltd
See LICENSE for details
"""

from karapace.core.instrumentation.tracer import Tracer
from threading import Condition


class OffsetWatcher:
    """Synchronization container for threads to wait until an offset is seen.

    This works under the assumption offsets are used only once, which should be
    correct as long as no unclean leader election is performed.
    """

    def __init__(self) -> None:
        # Condition used to protected _greatest_offset, any modifications to that object must
        # be performed with this condition acquired
        self._condition = Condition()
        self._greatest_offset = -1  # Would fail if initially this is 0 as it will be first offset ever.
        self._tracer = Tracer()

    def greatest_offset(self) -> int:
        with self._tracer.get_tracer().start_as_current_span(
            self._tracer.get_name_from_caller_with_class(self, self.greatest_offset)
        ):
            return self._greatest_offset

    def offset_seen(self, new_offset: int) -> None:
        with self._condition:
            self._greatest_offset = max(self._greatest_offset, new_offset)
            self._condition.notify_all()

    def wait_for_offset(self, expected_offset: int, timeout: float) -> bool:
        """Block until expected_offset is seen.

        Args:
            expected_offset: The message offset generated by the producer.
            timeout: How long the caller will wait for the offset in seconds.
        """
        with self._condition:
            return self._condition.wait_for(lambda: expected_offset <= self._greatest_offset, timeout=timeout)
