"""File system monitoring with watchdog."""

from pathlib import Path
from typing import Callable

from watchdog.observers import Observer
from watchdog.events import (
    FileSystemEventHandler,
    FileCreatedEvent,
    FileModifiedEvent,
    FileDeletedEvent,
    FileMovedEvent,
)

__all__ = ["FileEventHandler", "FileMonitor"]


class FileEventHandler(FileSystemEventHandler):
    def __init__(
        self,
        on_change: Callable[[Path], None],
        on_delete: Callable[[Path], None],
        should_ignore: Callable[[Path], bool],
    ):
        self.on_change = on_change
        self.on_delete = on_delete
        self.should_ignore = should_ignore

    def _handle_change(self, path: Path):
        if path.is_file() and not self.should_ignore(path):
            self.on_change(path)

    def _handle_delete(self, path: Path):
        if not self.should_ignore(path):
            self.on_delete(path)

    def on_created(self, event: FileCreatedEvent):
        if not event.is_directory:
            self._handle_change(Path(event.src_path))

    def on_modified(self, event: FileModifiedEvent):
        if not event.is_directory:
            self._handle_change(Path(event.src_path))

    def on_deleted(self, event: FileDeletedEvent):
        if not event.is_directory:
            self._handle_delete(Path(event.src_path))

    def on_moved(self, event: FileMovedEvent):
        if not event.is_directory:
            self._handle_delete(Path(event.src_path))
            self._handle_change(Path(event.dest_path))


class FileMonitor:
    def __init__(
        self,
        root_path: Path,
        on_change: Callable[[Path], None],
        on_delete: Callable[[Path], None],
        should_ignore: Callable[[Path], bool],
    ):
        self.root_path = root_path.resolve()
        self.handler = FileEventHandler(
            on_change=on_change,
            on_delete=on_delete,
            should_ignore=should_ignore,
        )
        self.observer = Observer()

    def start(self):
        self.observer.schedule(self.handler, str(self.root_path), recursive=True)
        self.observer.start()

    def stop(self):
        self.observer.stop()
        self.observer.join(timeout=5)

    def is_alive(self) -> bool:
        return self.observer.is_alive()
