from __future__ import annotations

import logging
import threading
from typing import TYPE_CHECKING

from watchdog.utils import BaseThread

if TYPE_CHECKING:
    from typing import Callable

    from watchdog.events import FileSystemEvent

logger = logging.getLogger(__name__)


class EventDebouncer(BaseThread):
    """Background thread for debouncing event handling.

    When an event is received, wait until the configured debounce interval
    passes before calling the callback.  If additional events are received
    before the interval passes, reset the timer and keep waiting.  When the
    debouncing interval passes, the callback will be called with a list of
    events in the order in which they were received.
    """

    def __init__(
        self,
        debounce_interval_seconds: int,
        events_callback: Callable[[list[FileSystemEvent]], None],
    ) -> None:
        super().__init__()
        self.debounce_interval_seconds = debounce_interval_seconds
        self.events_callback = events_callback

        self._events: list[FileSystemEvent] = []
        self._cond = threading.Condition()

    def handle_event(self, event: FileSystemEvent) -> None:
        with self._cond:
            self._events.append(event)
            self._cond.notify()

    def stop(self) -> None:
        with self._cond:
            super().stop()
            self._cond.notify()

    def run(self) -> None:
        with self._cond:
            while True:
                # Wait for first event (or shutdown).
                self._cond.wait()

                if self.debounce_interval_seconds:
                    # Wait for additional events (or shutdown) until the debounce interval passes.
                    while self.should_keep_running():
                        if not self._cond.wait(timeout=self.debounce_interval_seconds):
                            break

                if not self.should_keep_running():
                    break

                events = self._events
                self._events = []
                self.events_callback(events)
