# #region Test.PluginBase [C:3] [TYPE Module] [SEMANTICS test,plugin,base,abstract]
# @BRIEF Tests for core/plugin_base.py — PluginBase, PluginConfig.
# @RELATION BINDS_TO -> [PluginBase]

from pathlib import Path
import sys

sys.path.insert(0, str(Path(__file__).parent.parent.parent / "src"))

import pytest
from typing import Any


class TestPluginBase:
    """Verify PluginBase ABC contracts."""

    def test_cannot_instantiate_abstract_class(self):
        from src.core.plugin_base import PluginBase

        with pytest.raises(TypeError):
            PluginBase()

    def test_concrete_plugin_works(self):
        from src.core.plugin_base import PluginBase

        class TestPlugin(PluginBase):
            @property
            def id(self) -> str:
                return "test-plugin"

            @property
            def name(self) -> str:
                return "Test Plugin"

            @property
            def description(self) -> str:
                return "A test plugin"

            @property
            def version(self) -> str:
                return "1.0.0"

            def get_schema(self) -> dict[str, Any]:
                return {"type": "object", "properties": {}}

            async def execute(self, params: dict[str, Any]):
                return {"status": "ok"}

        plugin = TestPlugin()
        assert plugin.id == "test-plugin"
        assert plugin.name == "Test Plugin"
        assert plugin.description == "A test plugin"
        assert plugin.version == "1.0.0"

    def test_required_permission_format(self):
        from src.core.plugin_base import PluginBase

        class TestPlugin(PluginBase):
            @property
            def id(self) -> str:
                return "backup"

            @property
            def name(self) -> str:
                return "Backup"

            @property
            def description(self) -> str:
                return "Backup plugin"

            @property
            def version(self) -> str:
                return "1.0"

            def get_schema(self) -> dict[str, Any]:
                return {}

            async def execute(self, params: dict[str, Any]):
                pass

        plugin = TestPlugin()
        assert plugin.required_permission == "plugin:backup:execute"

    def test_ui_route_default_is_none(self):
        from src.core.plugin_base import PluginBase

        class TestPlugin(PluginBase):
            @property
            def id(self) -> str:
                return "test"

            @property
            def name(self) -> str:
                return "Test"

            @property
            def description(self) -> str:
                return "Test"

            @property
            def version(self) -> str:
                return "1.0"

            def get_schema(self) -> dict[str, Any]:
                return {}

            async def execute(self, params: dict[str, Any]):
                pass

        plugin = TestPlugin()
        assert plugin.ui_route is None


class TestPluginBaseAbstractBodies:
    """Cover abstract method bodies by calling super()."""

    @pytest.mark.asyncio
    async def test_id_abstract_body(self):
        from src.core.plugin_base import PluginBase

        class TestPlugin(PluginBase):
            @property
            def id(self):
                return super().id

            @property
            def name(self):
                return super().name

            @property
            def description(self):
                return super().description

            @property
            def version(self):
                return super().version

            def get_schema(self):
                return super().get_schema()

            async def execute(self, params):
                return await super().execute(params)

        plugin = TestPlugin()
        # These should execute the abstract bodies (with belief_scope: pass)
        assert plugin.id is None
        assert plugin.name is None
        assert plugin.description is None
        assert plugin.version is None
        assert plugin.get_schema() is None
        result = await plugin.execute({})
        assert result is None


class TestPluginConfig:
    """Verify PluginConfig Pydantic model."""

    def test_full_config(self):
        from src.core.plugin_base import PluginConfig

        config = PluginConfig(
            id="backup",
            name="Backup Plugin",
            description="Creates backups",
            version="2.1.0",
            ui_route="/plugins/backup",
            schema={"type": "object"},
        )
        assert config.id == "backup"
        assert config.name == "Backup Plugin"
        assert config.description == "Creates backups"
        assert config.version == "2.1.0"
        assert config.ui_route == "/plugins/backup"
        assert config.input_schema == {"type": "object"}

    def test_minimal_config(self):
        from src.core.plugin_base import PluginConfig

        config = PluginConfig(
            id="simple",
            name="Simple",
            description="Simple plugin",
            version="1.0",
            schema={},
        )
        assert config.id == "simple"
        assert config.ui_route is None
        assert config.input_schema == {}

    def test_config_serialization(self):
        from src.core.plugin_base import PluginConfig

        config = PluginConfig(
            id="test",
            name="Test",
            description="A plugin",
            version="0.1",
            schema={"type": "object", "properties": {"x": {"type": "string"}}},
        )
        data = config.model_dump(by_alias=True)
        assert data["id"] == "test"
        assert data["schema"] == {"type": "object", "properties": {"x": {"type": "string"}}}
        assert data["ui_route"] is None
# #endregion Test.PluginBase
