# #region Test.FilterStateModels [C:3] [TYPE Module] [SEMANTICS test,filter_state,models]
# @BRIEF Verify Pydantic filter-state models — creation, defaults, methods, and merge logic.
# @RELATION BINDS_TO -> [FilterStateModels]
# @TEST_EDGE: missing_filter_id -> get_extra_form_data returns empty dict
# @TEST_EDGE: empty_dataMask -> has_filters returns False
# @TEST_EDGE: append_non_list_fallback -> append key with non-list values falls through to override
import pytest

from src.models.filter_state import (
    DashboardURLFilterExtraction,
    ExtraFormDataMerge,
    FilterState,
    NativeFilterDataMask,
    ParsedNativeFilters,
)


class TestFilterStateModel:
    """Verify FilterState creation and defaults."""

    # #region test_filter_state_defaults [C:2] [TYPE Function]
    # @BRIEF FilterState with no args produces empty dicts for all three fields.
    def test_filter_state_defaults(self):
        fs = FilterState()
        assert fs.extraFormData == {}
        assert fs.filterState == {}
        assert fs.ownState == {}
    # #endregion test_filter_state_defaults

    # #region test_filter_state_all_fields [C:2] [TYPE Function]
    # @BRIEF FilterState with explicit values preserves every field.
    def test_filter_state_all_fields(self):
        fs = FilterState(
            extraFormData={"time_range": "2024 : 2025"},
            filterState={"value": ["admin"]},
            ownState={"owner": "user_1"},
        )
        assert fs.extraFormData == {"time_range": "2024 : 2025"}
        assert fs.filterState == {"value": ["admin"]}
        assert fs.ownState == {"owner": "user_1"}
    # #endregion test_filter_state_all_fields


class TestNativeFilterDataMaskModel:
    """Verify NativeFilterDataMask container methods."""

    # #region test_get_filter_ids [C:2] [TYPE Function]
    # @BRIEF get_filter_ids returns all keys from the filters dict.
    def test_get_filter_ids(self):
        mask = NativeFilterDataMask(filters={
            "NATIVE_FILTER_ABC": FilterState(extraFormData={"col": "a"}),
            "NATIVE_FILTER_XYZ": FilterState(extraFormData={"col": "b"}),
        })
        assert mask.get_filter_ids() == ["NATIVE_FILTER_ABC", "NATIVE_FILTER_XYZ"]
    # #endregion test_get_filter_ids

    # #region test_get_extra_form_data_existing [C:2] [TYPE Function]
    # @BRIEF get_extra_form_data returns extraFormData for a known filter ID.
    def test_get_extra_form_data_existing(self):
        mask = NativeFilterDataMask(filters={
            "NATIVE_FILTER_1": FilterState(extraFormData={"time_range": "Last week"}),
        })
        assert mask.get_extra_form_data("NATIVE_FILTER_1") == {"time_range": "Last week"}
    # #endregion test_get_extra_form_data_existing

    # #region test_get_extra_form_data_missing [C:2] [TYPE Function]
    # @BRIEF get_extra_form_data returns empty dict for unknown filter ID.
    def test_get_extra_form_data_missing(self):
        mask = NativeFilterDataMask(filters={
            "NATIVE_FILTER_1": FilterState(extraFormData={"col": "x"}),
        })
        assert mask.get_extra_form_data("NONEXISTENT_ID") == {}
    # #endregion test_get_extra_form_data_missing


class TestParsedNativeFiltersModel:
    """Verify ParsedNativeFilters query methods."""

    # #region test_has_filters_true [C:2] [TYPE Function]
    # @BRIEF has_filters returns True when dataMask is non-empty.
    def test_has_filters_true(self):
        parsed = ParsedNativeFilters(dataMask={"f1": {}, "f2": {}})
        assert parsed.has_filters() is True
    # #endregion test_has_filters_true

    # #region test_has_filters_false [C:2] [TYPE Function]
    # @BRIEF has_filters returns False when dataMask is empty.
    def test_has_filters_false(self):
        parsed = ParsedNativeFilters()
        assert parsed.has_filters() is False
    # #endregion test_has_filters_false

    # #region test_get_filter_count [C:2] [TYPE Function]
    # @BRIEF get_filter_count returns the number of entries in dataMask.
    def test_get_filter_count(self):
        parsed = ParsedNativeFilters(dataMask={"a": {}, "b": {}, "c": {}})
        assert parsed.get_filter_count() == 3
    # #endregion test_get_filter_count


class TestDashboardURLFilterExtractionModel:
    """Verify DashboardURLFilterExtraction creation and defaults."""

    # #region test_dashboard_url_extraction_all_fields [C:2] [TYPE Function]
    # @BRIEF All fields populated are preserved correctly.
    def test_dashboard_url_extraction_all_fields(self):
        filters = ParsedNativeFilters(dataMask={"f1": {}})
        extraction = DashboardURLFilterExtraction(
            url="https://superset/dashboard/42?native_filters=key1",
            dashboard_id="42",
            filter_type="permalink",
            filters=filters,
            success=False,
            error="partial extraction",
        )
        assert extraction.url == "https://superset/dashboard/42?native_filters=key1"
        assert extraction.dashboard_id == "42"
        assert extraction.filter_type == "permalink"
        assert extraction.filters is filters
        assert extraction.success is False
        assert extraction.error == "partial extraction"
    # #endregion test_dashboard_url_extraction_all_fields

    # #region test_dashboard_url_extraction_default_success [C:2] [TYPE Function]
    # @BRIEF success defaults to True when not specified.
    def test_dashboard_url_extraction_default_success(self):
        extraction = DashboardURLFilterExtraction(url="https://superset/dashboard/1")
        assert extraction.success is True
        assert extraction.error is None
        assert extraction.dashboard_id is None
    # #endregion test_dashboard_url_extraction_default_success


class TestExtraFormDataMergeModel:
    """Verify ExtraFormDataMerge configuration and merge logic."""

    # #region test_merge_default_config [C:2] [TYPE Function]
    # @BRIEF Default append_keys and override_keys match the documented lists.
    def test_merge_default_config(self):
        cfg = ExtraFormDataMerge()
        assert cfg.append_keys == ["filters", "extras", "columns", "metrics"]
        assert cfg.override_keys == ["time_range", "time_grain_sqla", "time_column", "granularity"]
    # #endregion test_merge_default_config

    # #region test_merge_override_keys [C:2] [TYPE Function]
    # @BRIEF Override keys replace original values entirely.
    def test_merge_override_keys(self):
        cfg = ExtraFormDataMerge()
        original = {"time_range": "2023 : 2024", "time_grain_sqla": "DAY"}
        new = {"time_range": "2024 : 2025", "time_grain_sqla": "MONTH"}
        result = cfg.merge(original, new)
        assert result["time_range"] == "2024 : 2025"
        assert result["time_grain_sqla"] == "MONTH"
    # #endregion test_merge_override_keys

    # #region test_merge_append_keys [C:2] [TYPE Function]
    # @BRIEF Append keys concatenate lists from original and new.
    def test_merge_append_keys(self):
        cfg = ExtraFormDataMerge()
        original = {"filters": [{"col": "a"}], "columns": ["x"]}
        new = {"filters": [{"col": "b"}], "columns": ["y", "z"]}
        result = cfg.merge(original, new)
        assert result["filters"] == [{"col": "a"}, {"col": "b"}]
        assert result["columns"] == ["x", "y", "z"]
    # #endregion test_merge_append_keys

    # #region test_merge_non_special_keys [C:2] [TYPE Function]
    # @BRIEF Keys not in override or append lists fall through — new replaces original.
    def test_merge_non_special_keys(self):
        cfg = ExtraFormDataMerge()
        original = {"custom_key": "old_value", "another": 1}
        new = {"custom_key": "new_value", "brand_new": True}
        result = cfg.merge(original, new)
        assert result["custom_key"] == "new_value"
        assert result["another"] == 1
        assert result["brand_new"] is True
    # #endregion test_merge_non_special_keys

    # #region test_merge_append_non_list_fallback [C:2] [TYPE Function]
    # @BRIEF Append key with non-list values falls through to simple override.
    def test_merge_append_non_list_fallback(self):
        cfg = ExtraFormDataMerge()
        original = {"filters": "not_a_list"}
        new = {"filters": ["real_filter"]}
        result = cfg.merge(original, new)
        assert result["filters"] == ["real_filter"]
    # #endregion test_merge_append_non_list_fallback


# #endregion Test.FilterStateModels
