"""
The filesystem events need an abstraction because on Windows there is a quirk where events are published before
they are synced. To alleviate the problem the events support a generic delay-system that can be utilized by the
implementation of the event class.
"""
import logging
import sys
from pathlib import Path
from typing import Union, Optional

logger = logging.getLogger(__name__)


class BaseFilesystemEvent(object):
    """
    Basic FS event for a path that features no metadata handling or delay. This is sufficient for systems where
    all events are guaranteed to be produced by the observer after they are visible from the filesystem.
    """

    __slots__ = ("path", "errors")

    def __init__(self, path: str, *args):
        self.path = Path(path)
        self.errors = 0

    def is_ready(self) -> bool:
        return True

    def is_error_stalled(self, inc: bool = False, limit: int = 8) -> bool:
        self.errors += inc
        return self.errors > limit


if sys.platform.startswith("win"):

    class WindowsFilesystemEvent(BaseFilesystemEvent):
        __slots__ = ("meta", "delayed")

        def __init__(self, path: str, meta: Optional[Union[bool, str]] = None, *args):
            BaseFilesystemEvent.__init__(self, path)
            if isinstance(meta, str):
                self.meta = Path(meta)
            else:
                self.meta = meta
            self.delayed = 0

        def is_ready(self) -> bool:
            if self.meta is None:
                return True
            elif isinstance(self.meta, Path):
                # move event with strict source checking (works when rename is actually a replace)
                if not self.meta.exists() and self.path.exists():
                    return True
            elif self.meta is False:
                if not self.path.exists():
                    return True
            elif self.path.exists():
                return True
            self.delayed += 1
            if self.delayed > 10:
                logger.info("Event reached delay limit but is still not fulfilled")  # just go to processing
                return True
            return False

    SchedulerFilesystemEvent = WindowsFilesystemEvent

else:
    SchedulerFilesystemEvent = BaseFilesystemEvent
