from __future__ import annotations

import re
from typing import Iterable, Protocol


class TextSignalDetector(Protocol):
    def detect(self, text: str) -> bool:
        raise NotImplementedError


class CodeFenceDetector:
    def detect(self, text: str) -> bool:
        return "```" in text


class InlineCodeDetector:
    _CODE_SYMBOLS = re.compile(r"[{};]|=>|::|#include")
    _CODE_OPERATORS = re.compile(r"[=+\-*/%<>]")
    _CODE_BRACKETS = re.compile(r"[()\[\]{}]")

    def detect(self, text: str) -> bool:
        if self._CODE_SYMBOLS.search(text):
            return True
        has_operator = self._CODE_OPERATORS.search(text) is not None
        has_brackets = self._CODE_BRACKETS.search(text) is not None
        if has_operator and has_brackets:
            return True
        return False


class MathFormulaDetector:
    _INLINE_LATEX = re.compile(r"\$[^$]+\$")
    _BLOCK_LATEX = re.compile(r"\$\$[\s\S]+?\$\$")
    _LATEX_COMMANDS = re.compile(r"\\(frac|sum|int|sqrt|alpha|beta|gamma|theta|pi|sigma)")
    _LATEX_DELIMS = re.compile(r"\\\(|\\\)|\\\[|\\\]")

    def detect(self, text: str) -> bool:
        if self._BLOCK_LATEX.search(text):
            return True
        if self._INLINE_LATEX.search(text):
            return True
        if self._LATEX_COMMANDS.search(text):
            return True
        return self._LATEX_DELIMS.search(text) is not None


class RememberEligibilityPolicy:
    def __init__(self, detectors: Iterable[TextSignalDetector] | None = None) -> None:
        self._detectors = list(detectors) if detectors is not None else [
            CodeFenceDetector(),
            InlineCodeDetector(),
            MathFormulaDetector(),
        ]

    def should_remember(self, text: str) -> bool:
        if not text:
            return False
        for detector in self._detectors:
            if detector.detect(text):
                return False
        return True