# #region TestTestDatasetDashboardRelations [C:2] [TYPE Module] [SEMANTICS test,dataset,dashboard,superset]
# @BRIEF Tests for test_dataset_dashboard_relations script (mocked Superset API, no real connection).
# @RELATION BINDS_TO -> [test_dataset_dashboard_relations_script]
# @TEST_EDGE: script_has_if_name_guard -> Module executes only under __main__
# @TEST_EDGE: test_function_calls_client -> Verifies client authentication and API calls
# @TEST_EDGE: dashboard_response_parsing -> Handles slices in dashboard
# @TEST_EDGE: dataset_response_parsing -> Handles dataset structure
# @TEST_EDGE: related_objects_dashboards -> Parses dashboards from related_objects
# @TEST_EDGE: related_objects_wrapped_result -> Handles result wrapper
# @TEST_EDGE: no_slices_in_dashboard -> Warns when slices missing
# @TEST_EDGE: related_objects_exception -> Logs error without crashing
import sys
from pathlib import Path
from unittest.mock import MagicMock, patch, call
import json

import pytest

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


class TestTestDatasetDashboardRelations:
    """Tests for test_dataset_dashboard_relations module."""

    def test_module_has_if_name_guard(self):
        """Structural: module has __main__ guard."""
        src_path = Path(__file__).parent.parent.parent / "src" / "scripts" / "test_dataset_dashboard_relations.py"
        source = src_path.read_text(encoding="utf-8")
        # Check that `if __name__ == "__main__":` or equivalent guard exists
        assert 'if __name__ == "__main__":' in source, "Module must have if __name__ guard"

    @patch("src.scripts.test_dataset_dashboard_relations.ConfigManager")
    @patch("src.scripts.test_dataset_dashboard_relations.SupersetClient")
    def test_test_function_calls_client_authenticate(
        self, MockSupersetClient, MockConfigManager
    ):
        """Happy: test_dashboard_dataset_relations authenticates and fetches dashboard/dataset."""
        from src.scripts.test_dataset_dashboard_relations import test_dashboard_dataset_relations

        # Mock environments
        env_mock = MagicMock()
        env_mock.name = "test-env"
        env_mock.url = "http://superset.test"
        MockConfigManager.return_value.get_environments.return_value = [env_mock]

        # Mock client
        mock_client = MagicMock()
        # Dashboard response with slices
        mock_client.network.request.side_effect = [
            # First call: GET /dashboard/13
            {
                "id": 13,
                "dashboard_title": "Test Dashboard",
                "published": True,
                "slices": [
                    {"slice_id": 1, "slice_name": "Chart 1", "datasource_id": 26, "datasource_type": "table"}
                ],
                "position_json": '{"DASHBOARD_VERSION_KEY": "v2"}',
            },
            # Second call: GET /dataset/26/related_objects
            {
                "dashboards": [
                    {"id": 13, "dashboard_title": "Test Dashboard"},
                    {"id": 14, "dashboard_title": "Another Dashboard"},
                ]
            },
        ]
        # get_dataset response
        mock_client.get_dataset.return_value = {
            "id": 26,
            "table_name": "test_table",
            "schema": "public",
            "database": {"database_name": "test_db"},
        }
        MockSupersetClient.return_value = mock_client

        # Patch sys.stdout to suppress prints
        with patch("sys.stdout"):
            test_dashboard_dataset_relations()

        mock_client.authenticate.assert_called_once()
        # Check that dashboard and dataset were fetched
        assert mock_client.network.request.call_count >= 2

    @patch("src.scripts.test_dataset_dashboard_relations.ConfigManager")
    @patch("src.scripts.test_dataset_dashboard_relations.SupersetClient")
    def test_no_slices_in_dashboard_warns(
        self, MockSupersetClient, MockConfigManager
    ):
        """Edge: dashboard without slices field logs warning."""
        from src.scripts.test_dataset_dashboard_relations import test_dashboard_dataset_relations

        env_mock = MagicMock()
        env_mock.name = "test-env"
        env_mock.url = "http://superset.test"
        MockConfigManager.return_value.get_environments.return_value = [env_mock]

        mock_client = MagicMock()
        mock_client.network.request.side_effect = [
            # Dashboard without slices key
            {
                "id": 13,
                "dashboard_title": "No Slices Dashboard",
                "published": True,
            },
            # related_objects
            {"dashboards": []},
        ]
        mock_client.get_dataset.return_value = {
            "id": 26,
            "table_name": "test_table",
        }
        MockSupersetClient.return_value = mock_client

        with patch("sys.stdout"):
            test_dashboard_dataset_relations()

        # Should not crash — just warns about missing slices
        mock_client.authenticate.assert_called_once()

    @patch("src.scripts.test_dataset_dashboard_relations.ConfigManager")
    @patch("src.scripts.test_dataset_dashboard_relations.SupersetClient")
    def test_related_objects_wrapped_in_result(
        self, MockSupersetClient, MockConfigManager
    ):
        """Edge: related_objects response wrapped in 'result' key."""
        from src.scripts.test_dataset_dashboard_relations import test_dashboard_dataset_relations

        env_mock = MagicMock()
        env_mock.name = "test-env"
        MockConfigManager.return_value.get_environments.return_value = [env_mock]

        mock_client = MagicMock()
        mock_client.network.request.side_effect = [
            {"id": 13, "dashboard_title": "Test", "slices": []},
            {"result": {"dashboards": [{"id": 13, "dashboard_title": "Wrapped"}]}},
        ]
        mock_client.get_dataset.return_value = {"id": 26, "table_name": "t"}
        MockSupersetClient.return_value = mock_client

        with patch("sys.stdout"):
            test_dashboard_dataset_relations()

        mock_client.authenticate.assert_called_once()

    @patch("src.scripts.test_dataset_dashboard_relations.ConfigManager")
    @patch("src.scripts.test_dataset_dashboard_relations.SupersetClient")
    def test_related_objects_exception_handled(
        self, MockSupersetClient, MockConfigManager
    ):
        """Edge: exception in related_objects fetch is caught, not propagated."""
        from src.scripts.test_dataset_dashboard_relations import test_dashboard_dataset_relations

        env_mock = MagicMock()
        env_mock.name = "test-env"
        MockConfigManager.return_value.get_environments.return_value = [env_mock]

        mock_client = MagicMock()

        def request_side_effect(method=None, endpoint=None, **kwargs):
            if "related_objects" in (endpoint or ""):
                raise RuntimeError("API unavailable")
            return {"id": 13, "dashboard_title": "Test", "slices": []}

        mock_client.network.request.side_effect = request_side_effect
        mock_client.get_dataset.return_value = {"id": 26, "table_name": "t"}
        MockSupersetClient.return_value = mock_client

        with patch("sys.stdout"):
            # Should not raise — exception is caught and logged
            test_dashboard_dataset_relations()

        mock_client.authenticate.assert_called_once()

    @patch("src.scripts.test_dataset_dashboard_relations.ConfigManager")
    @patch("src.scripts.test_dataset_dashboard_relations.SupersetClient")
    def test_no_environments_logs_error(
        self, MockSupersetClient, MockConfigManager
    ):
        """Edge: no configured environments logs error and returns."""
        from src.scripts.test_dataset_dashboard_relations import test_dashboard_dataset_relations

        MockConfigManager.return_value.get_environments.return_value = []

        with patch("sys.stdout"):
            test_dashboard_dataset_relations()

        # Should not crash, but authenticate should NOT be called
        MockSupersetClient.return_value.authenticate.assert_not_called()
# #endregion TestTestDatasetDashboardRelations
