# #region Test.DatasetsPreviewMixin [C:3] [TYPE Module] [SEMANTICS test, dataset, preview, compile, query]
# @BRIEF Tests for core/superset_client/_datasets_preview.py — SupersetDatasetsPreviewMixin.
# @RELATION BINDS_TO -> [SupersetDatasetsPreviewMixin]

from pathlib import Path
import sys

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

from unittest.mock import AsyncMock, MagicMock, patch

import pytest


class TestDatasetsPreviewMixin:
    """Test SupersetDatasetsPreviewMixin methods."""

    @pytest.fixture
    def mixin(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m.client = MagicMock()
        m.client.request = AsyncMock()
        m.get_dataset = AsyncMock()
        m.build_dataset_preview_query_context = MagicMock(
            return_value={
                "datasource": {"id": 1, "type": "table"},
                "queries": [{"metrics": ["count"], "columns": [], "filters": []}],
                "form_data": {"datasource": "1__table"},
                "result_format": "json",
                "result_type": "query",
                "force": True,
            }
        )
        m.build_dataset_preview_legacy_form_data = MagicMock(
            return_value={
                "datasource": "1__table",
                "metrics": ["count"],
                "result_format": "json",
                "result_type": "query",
                "force": True,
            }
        )
        m._extract_compiled_sql_from_preview_response = MagicMock(
            return_value={"compiled_sql": "SELECT 1", "response_diagnostics": []}
        )
        return m

    # ── compile_dataset_preview ──

    @pytest.mark.asyncio
    async def test_compile_dataset_preview_first_strategy_succeeds(self, mixin):
        mixin.get_dataset.return_value = {"result": {"id": 1}}
        mixin.client.request.return_value = {"compiled_sql": "SELECT 1"}
        result = await mixin.compile_dataset_preview(
            dataset_id=1, template_params={"schema": "public"}, effective_filters=[{"col": "status", "val": "active"}]
        )
        assert result["compiled_sql"] == "SELECT 1"
        assert result["dataset_id"] == 1
        assert "endpoint_kind" in result
        assert "strategy_attempts" in result

    @pytest.mark.asyncio
    async def test_compile_dataset_preview_all_strategies_fail(self, mixin):
        mixin.get_dataset.return_value = {"result": {"id": 1}}
        mixin.client.request.side_effect = Exception("API error")

        from src.core.utils.network import SupersetAPIError

        with pytest.raises(SupersetAPIError, match="Superset preview compilation failed"):
            await mixin.compile_dataset_preview(dataset_id=1)

    @pytest.mark.asyncio
    async def test_compile_dataset_preview_get_dataset_non_dict(self, mixin):
        mixin.get_dataset.return_value = "raw_response"
        mixin.client.request.return_value = {"compiled_sql": "SELECT 1"}
        result = await mixin.compile_dataset_preview(dataset_id=1)
        assert result["compiled_sql"] == "SELECT 1"

    @pytest.mark.asyncio
    async def test_compile_dataset_preview_no_template_params(self, mixin):
        # Note: fixture sets mixin._extract_compiled_sql_from_preview_response to return
        # {"compiled_sql": "SELECT 1"}, so this overrides client.request return value.
        # The actual endpoint returns whatever the mock provides, but the extraction
        # is mocked to "SELECT 1". This test verifies that calling without params works.
        mixin.get_dataset.return_value = {"result": {"id": 1}}
        mixin.client.request.return_value = {"compiled_sql": "SELECT 1"}
        result = await mixin.compile_dataset_preview(dataset_id=1)
        assert result["compiled_sql"] == "SELECT 1"

    # ── build_dataset_preview_query_context ──

    def test_build_dataset_preview_query_context_basic(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m._normalize_effective_filters_for_query_context = MagicMock(
            return_value={
                "filters": [{"col": "status", "op": "==", "val": "active"}],
                "extra_form_data": {},
                "diagnostics": [],
            }
        )
        result = m.build_dataset_preview_query_context(
            dataset_id=1,
            dataset_record={
                "id": 1,
                "table_name": "users",
                "schema": "public",
                "datasource": {"id": 1, "type": "table"},
            },
            template_params={"param1": "val1"},
            effective_filters=[{"col": "status", "val": "active"}],
        )
        assert result["datasource"]["id"] == 1
        assert result["datasource"]["type"] == "table"
        assert result["form_data"]["datasource"] == "1__table"
        assert len(result["queries"]) == 1
        assert result["queries"][0]["schema"] == "public"
        assert result["queries"][0]["row_limit"] == 1000
        assert result["queries"][0]["url_params"] == {"param1": "val1"}

    def test_build_dataset_preview_query_context_with_template_params_from_dataset(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m._normalize_effective_filters_for_query_context = MagicMock(
            return_value={"filters": [], "extra_form_data": {}, "diagnostics": []}
        )
        result = m.build_dataset_preview_query_context(
            dataset_id=1,
            dataset_record={
                "id": 1,
                "table_name": "users",
                "template_params": '{"dataset_param": "value"}',
            },
            template_params={"param1": "val1"},
            effective_filters=[],
        )
        # Dataset template_params should be merged (setdefault, so existing keys take precedence)
        assert result["queries"][0]["url_params"]["param1"] == "val1"
        assert result["queries"][0]["url_params"]["dataset_param"] == "value"

    def test_build_dataset_preview_query_context_with_bad_template_params(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m._normalize_effective_filters_for_query_context = MagicMock(
            return_value={"filters": [], "extra_form_data": {}, "diagnostics": []}
        )
        with patch("src.core.superset_client._datasets_preview.app_logger") as mock_log:
            result = m.build_dataset_preview_query_context(
                dataset_id=1,
                dataset_record={
                    "id": 1,
                    "table_name": "users",
                    "template_params": "{invalid json}",
                },
                template_params={},
                effective_filters=[],
            )
            mock_log.explore.assert_called_once()
            assert result["queries"][0]["url_params"] == {}

    def test_build_dataset_preview_query_context_with_filters(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m._normalize_effective_filters_for_query_context = MagicMock(
            return_value={
                "filters": [{"col": "status", "op": "==", "val": "active"}],
                "extra_form_data": {"time_range": "Last week"},
                "diagnostics": [],
            }
        )
        result = m.build_dataset_preview_query_context(
            dataset_id=1,
            dataset_record={"id": 1, "table_name": "users"},
            template_params={},
            effective_filters=[{"col": "status", "val": "active"}],
        )
        # Filters should be in extra_form_data and in the query
        assert "time_range" in result["form_data"]["extra_form_data"]
        assert result["form_data"]["extra_form_data"]["time_range"] == "Last week"
        assert result["queries"][0]["filters"] == [{"col": "status", "op": "==", "val": "active"}]

    def test_build_dataset_preview_query_context_datasource_passthrough(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m._normalize_effective_filters_for_query_context = MagicMock(
            return_value={"filters": [], "extra_form_data": {}, "diagnostics": []}
        )
        result = m.build_dataset_preview_query_context(
            dataset_id=1,
            dataset_record={
                "id": 1,
                "table_name": "users",
                "datasource": {"id": 99, "type": "query"},
            },
            template_params={},
            effective_filters=[],
        )
        # The datasource from the record should override
        assert result["datasource"]["id"] == 99
        assert result["datasource"]["type"] == "query"

    # ── build_dataset_preview_legacy_form_data ──

    def test_build_dataset_preview_legacy_form_data_basic(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m.build_dataset_preview_query_context = MagicMock(
            return_value={
                "queries": [{
                    "metrics": ["count"],
                    "columns": [],
                    "orderby": [],
                    "annotation_layers": [],
                    "row_limit": 1000,
                    "series_limit": 0,
                    "url_params": {},
                    "applied_time_extras": {},
                    "extras": {"where": ""},
                }],
                "form_data": {"datasource": "1__table"},
                "result_format": "json",
                "result_type": "query",
                "force": True,
            }
        )
        result = m.build_dataset_preview_legacy_form_data(1, {}, {}, [])
        assert result["metrics"] == ["count"]
        assert result["result_format"] == "json"
        assert result["result_type"] == "query"
        assert result["force"] is True
        assert "datasource" not in result  # popped

    def test_build_dataset_preview_legacy_form_data_with_extras(self):
        from src.core.superset_client._datasets_preview import (
            SupersetDatasetsPreviewMixin,
        )

        m = SupersetDatasetsPreviewMixin()
        m.build_dataset_preview_query_context = MagicMock(
            return_value={
                "queries": [{
                    "metrics": ["count"],
                    "columns": [],
                    "orderby": [],
                    "annotation_layers": [],
                    "row_limit": 1000,
                    "series_limit": 0,
                    "url_params": {},
                    "applied_time_extras": {},
                    "extras": {"where": "1=1"},
                    "time_range": "Last 7 days",
                }],
                "form_data": {},
                "result_format": "json",
                "result_type": "query",
                "force": False,
            }
        )
        result = m.build_dataset_preview_legacy_form_data(1, {}, {}, [])
        assert result["extras"]["where"] == "1=1"
        assert result["time_range"] == "Last 7 days"
        assert result["force"] is False
# #endregion Test.DatasetsPreviewMixin
