"""Tests for modules/stealth/ — Stealth module import and structure validation."""

import inspect
import importlib
import os
import sys
from unittest.mock import MagicMock, patch

import pytest

from modules.base import BaseModule


# All stealth modules defined in modules/stealth/__init__.py
STEALTH_MODULE_NAMES = [
    "MacManager",
    "ProcessDisguise",
    "LogSuppression",
    "EncryptedStorage",
    "TmpfsManager",
    "Watchdog",
    "AntiForensics",
    "TrafficMimicry",
    "JA3Spoofer",
    "IDSTester",
    "LKMRootkit",
    "OverlayfsManager",
]

STEALTH_MODULE_DOTTED = [
    "modules.stealth.mac_manager",
    "modules.stealth.process_disguise",
    "modules.stealth.log_suppression",
    "modules.stealth.encrypted_storage",
    "modules.stealth.tmpfs_manager",
    "modules.stealth.watchdog",
    "modules.stealth.anti_forensics",
    "modules.stealth.traffic_mimicry",
    "modules.stealth.ja3_spoofer",
    "modules.stealth.ids_tester",
    "modules.stealth.lkm_rootkit",
    "modules.stealth.overlayfs_manager",
]


class TestStealthModulesImportable:

    @pytest.mark.parametrize("dotted_path", STEALTH_MODULE_DOTTED)
    def test_all_stealth_modules_importable(self, dotted_path):
        """Each stealth module file can be imported without errors."""
        mod = importlib.import_module(dotted_path)
        assert mod is not None


class TestStealthModulesAreBaseModule:

    @pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
    def test_stealth_modules_are_base_module(self, class_name):
        """Each stealth module class is a subclass of BaseModule."""
        import modules.stealth as stealth_pkg
        cls = getattr(stealth_pkg, class_name)
        assert issubclass(cls, BaseModule), f"{class_name} is not a BaseModule subclass"


class TestStealthModuleAttributes:

    @pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
    def test_stealth_module_attributes(self, class_name):
        """Each stealth module has required class attributes: name, module_type, priority."""
        import modules.stealth as stealth_pkg
        cls = getattr(stealth_pkg, class_name)

        assert hasattr(cls, "name"), f"{class_name} missing 'name'"
        assert hasattr(cls, "module_type"), f"{class_name} missing 'module_type'"
        assert hasattr(cls, "priority"), f"{class_name} missing 'priority'"
        assert hasattr(cls, "dependencies"), f"{class_name} missing 'dependencies'"
        assert hasattr(cls, "requires_root"), f"{class_name} missing 'requires_root'"

        # name should not be 'unnamed' (BaseModule default)
        assert cls.name != "unnamed", f"{class_name} still has default name 'unnamed'"

        # module_type should be 'stealth'
        assert cls.module_type == "stealth", f"{class_name} module_type is '{cls.module_type}', expected 'stealth'"

        # priority should be an integer
        assert isinstance(cls.priority, int), f"{class_name} priority is not an int"

        # dependencies should be a list
        assert isinstance(cls.dependencies, list), f"{class_name} dependencies is not a list"

        # Check abstract methods are implemented
        for method_name in ("start", "stop", "status", "configure"):
            method = getattr(cls, method_name, None)
            assert method is not None, f"{class_name} missing method '{method_name}'"
            assert callable(method), f"{class_name}.{method_name} is not callable"


class TestStealthModuleInstantiate:

    @pytest.mark.parametrize("class_name", STEALTH_MODULE_NAMES)
    def test_stealth_module_instantiate(self, class_name, mock_bus, mock_state, mock_config):
        """Each stealth module can be instantiated with mock bus/state/config."""
        import modules.stealth as stealth_pkg
        cls = getattr(stealth_pkg, class_name)

        # Instantiate (should not crash)
        instance = cls(bus=mock_bus, state=mock_state, config=mock_config)

        assert instance is not None
        assert instance.bus is mock_bus
        assert instance.state is mock_state
        assert instance.config is mock_config
        assert instance._running is False
