"""BanSubstringsScanner for meshulash-guard SDK.

Blocks text containing any of a configurable list of banned substrings.
Substrings are loaded from a Python list or from a local text file (one
substring per line) at instantiation time — fail-fast, not at scan time.
The server performs the actual matching; the SDK is a pure config serializer.

STRING mode = substring match anywhere in the text.
WORD mode = word-boundary match (whole words only).
"""

from __future__ import annotations

from pathlib import Path

from ..enums import Action, _StrValueMixin
from .base import BaseScanner


class MatchType(_StrValueMixin):
    """Match mode for BanSubstringsScanner.

    STRING = substring can appear anywhere in the text.
    WORD   = substring must appear as a whole word (word-boundary match).
    """

    STRING = "string"
    WORD = "word"


class BanSubstringsScanner(BaseScanner):
    """Scanner that blocks text containing any banned substring.

    Substrings are loaded from a Python list or from a local text file
    (one substring per line, blank lines ignored) at instantiation time.
    This is fail-fast: file I/O errors raise ValueError at construction, not
    at scan time. The server performs the actual substring matching.

    Args:
        substrings: A list of strings, a file path (str or Path) to a text
            file with one substring per line, or a pathlib.Path object.
            Blank lines in files are automatically filtered out.
        match_type: MatchType.STRING (substring anywhere) or MatchType.WORD
            (word-boundary match). Defaults to STRING.
        case_sensitive: Whether matching is case-sensitive. Defaults to False.
        action: Action to take when a banned substring is found. Defaults
            to BLOCK.

    Raises:
        ValueError: If the file cannot be read, or if the resulting
            substring list is empty.
    """

    def __init__(
        self,
        substrings: list[str] | str | Path,
        match_type: MatchType = MatchType.STRING,
        case_sensitive: bool = False,
        action: Action = Action.BLOCK,
    ) -> None:
        if isinstance(substrings, list):
            loaded = list(substrings)
        else:
            # str or Path — read from file at instantiation (fail-fast)
            file_path = Path(substrings)
            try:
                raw = file_path.read_text(encoding="utf-8").splitlines()
            except OSError as exc:
                raise ValueError(
                    f"BanSubstringsScanner could not read substrings file "
                    f"{str(file_path)!r}: {exc}"
                ) from exc
            loaded = [ln for ln in raw if ln.strip()]

        if not loaded:
            raise ValueError(
                "BanSubstringsScanner requires at least one substring. "
                "The provided list or file contained no non-blank entries."
            )

        self._substrings = loaded
        self._match_type = match_type
        self._case_sensitive = case_sensitive
        self._action = action

    def to_guardline_spec(self) -> dict:
        """Return a flat guardline spec dict for this scanner configuration."""
        return {
            "name": "BanSubstringsScanner",
            "action": str(self._action),
            "substrings": self._substrings,
            "match_type": str(self._match_type),
            "case_sensitive": self._case_sensitive,
            "level": 4,
        }
