# Copyright 2025 Softwell S.r.l.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Tests for Plugin Configuration sys_app and server persistence methods."""

from pathlib import Path
from unittest.mock import MagicMock

from genro_asgi.sys_applications.plugin_config import Application


class TestPluginConfigApplication:
    """Tests for plugin_config Application (GUI sys_app)."""

    def _make_app(self) -> Application:
        """Create Application instance."""
        return Application()

    def test_init_creates_router(self) -> None:
        """Application creates main router."""
        app = self._make_app()
        assert app.main is not None
        assert app.main.name == "main"

    def test_index_returns_html(self) -> None:
        """Index endpoint returns HTML content."""
        app = self._make_app()
        result = app.index()
        assert "<!DOCTYPE html>" in result

    def test_tree_returns_dict(self) -> None:
        """Tree endpoint returns serialized routing tree."""
        mock_server = MagicMock()
        mock_server.router.nodes.return_value = {}
        app = self._make_app()
        app._routing_parent = mock_server
        result = app.tree()
        assert isinstance(result, dict)

    def test_config_delegates_to_server(self) -> None:
        """Config endpoint delegates to server.get_plugin_config()."""
        mock_server = MagicMock()
        mock_server.get_plugin_config.return_value = {"router_path": "", "plugin_info": {}}
        app = self._make_app()
        app._routing_parent = mock_server
        result = app.config(router_path="", entry="")
        mock_server.get_plugin_config.assert_called_once_with(router_path="", entry="")
        assert result == {"router_path": "", "plugin_info": {}}

    def test_save_delegates_to_server(self) -> None:
        """Save endpoint delegates to server.save_plugin_config()."""
        mock_server = MagicMock()
        mock_server.save_plugin_config.return_value = {"ok": True, "file": "/tmp/plugin_config.json"}
        app = self._make_app()
        app._routing_parent = mock_server
        result = app.save()
        mock_server.save_plugin_config.assert_called_once()
        assert result["ok"] is True

    def test_revert_delegates_to_server(self) -> None:
        """Revert endpoint delegates to server.revert_plugin_config()."""
        mock_server = MagicMock()
        mock_server.revert_plugin_config.return_value = {"ok": True}
        app = self._make_app()
        app._routing_parent = mock_server
        result = app.revert()
        mock_server.revert_plugin_config.assert_called_once()
        assert result["ok"] is True

    def test_apply_delegates_to_server(self) -> None:
        """Apply endpoint delegates to server.set_plugin_config()."""
        mock_server = MagicMock()
        mock_server.set_plugin_config.return_value = {"ok": True}
        app = self._make_app()
        app._routing_parent = mock_server
        result = app.apply(router_path="", plugin_name="logging", target="_all_", enabled=True)
        mock_server.set_plugin_config.assert_called_once_with(
            router_path="", plugin_name="logging", target="_all_", enabled=True,
        )
        assert result["ok"] is True


class TestServerPluginConfigPersistence:
    """Tests for AsgiServer plugin config persistence methods."""

    def _make_server(self, tmp_path: Path) -> MagicMock:
        """Create a mock server with plugin config methods wired up."""
        from genro_asgi.server.server import AsgiServer

        server = MagicMock(spec=AsgiServer)
        server.base_dir = tmp_path
        server.logger = MagicMock()

        # Wire up the real property and methods
        server.plugin_config_file = tmp_path / "plugin_config.json"

        # Use real method implementations bound to mock
        server._load_persisted_config = lambda: AsgiServer._load_persisted_config(server)
        server._snapshot_all_config = lambda: AsgiServer._snapshot_all_config(server)
        server.apply_persisted_config = lambda: AsgiServer.apply_persisted_config(server)
        server.save_plugin_config = lambda: AsgiServer.save_plugin_config(server)
        server.revert_plugin_config = lambda: AsgiServer.revert_plugin_config(server)

        return server

    def test_plugin_config_file_path(self, tmp_path: Path) -> None:
        """plugin_config_file returns path in base_dir."""
        server = self._make_server(tmp_path)
        assert server.plugin_config_file == tmp_path / "plugin_config.json"

    def test_apply_persisted_config_no_file(self, tmp_path: Path) -> None:
        """apply_persisted_config does nothing when no config file exists."""
        server = self._make_server(tmp_path)
        server.apply_persisted_config()

    def test_load_persisted_config_returns_empty(self, tmp_path: Path) -> None:
        """_load_persisted_config returns empty dict when file missing."""
        server = self._make_server(tmp_path)
        result = server._load_persisted_config()
        assert result == {}

    def test_load_persisted_config_reads_file(self, tmp_path: Path) -> None:
        """_load_persisted_config reads JSON file."""
        config_file = tmp_path / "plugin_config.json"
        config_file.write_text('{"_root_": {"_all_": {"logging": {"enabled": true}}}}')
        server = self._make_server(tmp_path)
        result = server._load_persisted_config()
        assert result == {"_root_": {"_all_": {"logging": {"enabled": True}}}}

    def test_revert_no_file(self, tmp_path: Path) -> None:
        """revert_plugin_config returns message when no file."""
        server = self._make_server(tmp_path)
        result = server.revert_plugin_config()
        assert result["ok"] is True
        assert "No saved config" in result["message"]
