"""Tests for utils/filters.py -- binary extraction and filtering logic."""

import pytest

from astrix_openclaw_scanner.utils.filters import (
    extract_binary_from_commandline,
    extract_binary_name,
    is_filtered_binary,
)

# ── extract_binary_name ─────────────────────────────────────────────────────

class TestExtractBinaryName:
    """Tests for extract_binary_name()."""

    def test_windows_path(self):
        result = extract_binary_name(
            "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
            is_windows=True,
        )
        assert result == "chrome"

    def test_unix_path(self):
        result = extract_binary_name("/usr/bin/openclaw-agent", is_windows=False)
        assert result == "openclaw-agent"

    def test_bare_filename_with_extension(self):
        assert extract_binary_name("chrome.exe", is_windows=True) == "chrome"

    def test_bare_filename_no_extension(self):
        assert extract_binary_name("openclaw-agent", is_windows=False) == "openclaw-agent"

    def test_strips_extension_via_stem(self):
        assert extract_binary_name("notepad.exe", is_windows=True) == "notepad"
        assert extract_binary_name("OpenClaw.app", is_windows=False) == "openclaw"

    def test_lowercases(self):
        assert extract_binary_name("Chrome.EXE", is_windows=True) == "chrome"
        assert extract_binary_name("OpenClaw-Agent", is_windows=False) == "openclaw-agent"

    def test_empty_string(self):
        assert extract_binary_name("") == ""

    def test_none(self):
        assert extract_binary_name(None) == ""

    def test_whitespace_stripped(self):
        assert extract_binary_name("  chrome.exe  ", is_windows=True) == "chrome"

    def test_windows_backslash_on_posix_hint_is_wrong(self):
        # With is_windows=False, backslash is NOT treated as separator
        result = extract_binary_name("C:\\Users\\chrome.exe", is_windows=False)
        # PurePosixPath treats the whole thing as a filename
        assert result != "chrome"

    def test_windows_backslash_on_windows_hint_is_correct(self):
        result = extract_binary_name("C:\\Users\\chrome.exe", is_windows=True)
        assert result == "chrome"


# ── extract_binary_from_commandline ──────────────────────────────────────────

class TestExtractBinaryFromCommandline:
    """Tests for extract_binary_from_commandline()."""

    def test_simple_commandline(self):
        assert extract_binary_from_commandline("openclaw-agent --serve") == "openclaw-agent"

    def test_quoted_path(self):
        result = extract_binary_from_commandline(
            '"C:\\Program Files\\openclaw\\agent.exe" --flag'
        )
        assert result == "C:\\Program Files\\openclaw\\agent.exe"

    def test_unix_path_with_args(self):
        result = extract_binary_from_commandline("/opt/openclaw/agent --daemon")
        assert result == "/opt/openclaw/agent"

    def test_empty_string(self):
        assert extract_binary_from_commandline("") == ""

    def test_none(self):
        assert extract_binary_from_commandline(None) == ""

    def test_single_token(self):
        assert extract_binary_from_commandline("agent") == "agent"

    def test_malformed_quotes_raises(self):
        """Unmatched quotes should raise (caught by aggregator try/except)."""
        with pytest.raises(ValueError):
            extract_binary_from_commandline('"unmatched quote')


# ── is_filtered_binary ───────────────────────────────────────────────────────

class TestIsFilteredBinary:
    """Tests for is_filtered_binary()."""

    # -- Noise that should be filtered --

    @pytest.mark.parametrize("binary", [
        "chrome", "msedge", "firefox", "brave", "opera", "iexplore", "island",
        "safari",
    ])
    def test_browsers_filtered(self, binary):
        assert is_filtered_binary(binary) is True

    @pytest.mark.parametrize("binary", [
        "notepad", "textedit", "sublime", "vscode", "code",
    ])
    def test_editors_filtered(self, binary):
        assert is_filtered_binary(binary) is True

    @pytest.mark.parametrize("binary", [
        "winword", "excel", "powerpnt", "outlook", "onenote",
        "msaccess", "mspub", "acrord32", "acrobat",
    ])
    def test_office_filtered(self, binary):
        assert is_filtered_binary(binary) is True

    @pytest.mark.parametrize("binary", [
        "preview", "pages", "numbers", "keynote",
    ])
    def test_macos_apps_filtered(self, binary):
        assert is_filtered_binary(binary) is True

    def test_self_detection_filtered(self):
        assert is_filtered_binary("astrix-openclaw-scanner") is True

    @pytest.mark.parametrize("binary", ["ls", "find", "grep"])
    def test_utilities_exact_filtered(self, binary):
        assert is_filtered_binary(binary) is True

    def test_tmux_filtered(self):
        assert is_filtered_binary("tmux") is True

    # -- Real events that should NOT be filtered --

    @pytest.mark.parametrize("binary", [
        "openclaw-agent", "clawdbot-agent", "moltbot", "agent",
    ])
    def test_real_events_not_filtered(self, binary):
        assert is_filtered_binary(binary) is False

    # -- Edge cases --

    def test_empty_string_not_filtered(self):
        assert is_filtered_binary("") is False

    def test_case_insensitive_via_extract(self):
        # The binary name should already be lowercased by extract_binary_name,
        # but is_filtered_binary itself works on whatever is passed in.
        assert is_filtered_binary("chrome") is True
        assert is_filtered_binary("CHROME") is False  # patterns are lowercase

    def test_tools_not_matching_ls(self):
        """'tools' should NOT be filtered -- 'ls' is an exact match only."""
        assert is_filtered_binary("tools") is False

    def test_substring_match_google_chrome(self):
        """'google chrome' should match because 'chrome' is a substring."""
        assert is_filtered_binary("google chrome") is True
