"""Matcher Protocol and implementations."""

from __future__ import annotations

from typing import Protocol, runtime_checkable


@runtime_checkable
class Matcher(Protocol):
    def matches(self, value: object) -> bool: ...


class AnyMatcher:
    def matches(self, value: object) -> bool:
        return True


class EqMatcher:
    def __init__(self, expected: object) -> None:
        self._expected = expected

    def matches(self, value: object) -> bool:
        if type(value) is not type(self._expected):
            return False
        return value == self._expected


class LtMatcher:
    def __init__(self, threshold: int | float) -> None:
        self._threshold = threshold

    def matches(self, value: object) -> bool:
        if isinstance(value, bool) or not isinstance(value, (int, float)):
            return False
        return value < self._threshold


class GtMatcher:
    def __init__(self, threshold: int | float) -> None:
        self._threshold = threshold

    def matches(self, value: object) -> bool:
        if isinstance(value, bool) or not isinstance(value, (int, float)):
            return False
        return value > self._threshold


class NotMatcher:
    def __init__(self, inner: Matcher) -> None:
        self._inner = inner

    def matches(self, value: object) -> bool:
        return not self._inner.matches(value)


class AndMatcher:
    def __init__(self, matchers: list[Matcher]) -> None:
        self._matchers = matchers

    def matches(self, value: object) -> bool:
        return all(m.matches(value) for m in self._matchers)


class OrMatcher:
    def __init__(self, matchers: list[Matcher]) -> None:
        self._matchers = matchers

    def matches(self, value: object) -> bool:
        return any(m.matches(value) for m in self._matchers)
