# #region Test.LayoutUtils [C:2] [TYPE Module] [SEMANTICS test, layout, position, json, banner]
# @BRIEF Tests for core/superset_client/_layout_utils.py — pure position JSON manipulation.
# @RELATION BINDS_TO -> [LayoutUtils]

from pathlib import Path
import sys

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

import pytest


class TestParsePositionJson:
    """parse_position_json: str/dict/None -> dict."""

    def test_parses_json_string(self):
        from src.core.superset_client._layout_utils import parse_position_json

        result = parse_position_json('{"GRID_ID": {"children": []}}')
        assert result == {"GRID_ID": {"children": []}}

    def test_empty_string_returns_empty_dict(self):
        from src.core.superset_client._layout_utils import parse_position_json

        result = parse_position_json("")
        assert result == {}

    def test_whitespace_string_returns_empty_dict(self):
        from src.core.superset_client._layout_utils import parse_position_json

        result = parse_position_json("   ")
        assert result == {}

    def test_dict_passthrough(self):
        from src.core.superset_client._layout_utils import parse_position_json

        raw = {"GRID_ID": {"children": []}}
        result = parse_position_json(raw)
        assert result is raw

    def test_none_returns_empty_dict(self):
        from src.core.superset_client._layout_utils import parse_position_json

        result = parse_position_json(None)
        assert result == {}

    def test_invalid_json_raises(self):
        from src.core.superset_client._layout_utils import parse_position_json

        with pytest.raises(Exception):
            parse_position_json("{invalid}")


class TestEstimateMarkdownHeight:
    """_estimate_markdown_height: content -> int height."""

    def test_empty_content_returns_min_height(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        assert _estimate_markdown_height("") == 19

    def test_short_content_returns_min_height(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        assert _estimate_markdown_height("short text") == 19

    def test_long_content_returns_larger_height(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        text = "word " * 200  # ~1000 chars => ~25 text lines
        height = _estimate_markdown_height(text)
        assert height >= 19
        assert height <= 200

    def test_html_content_counts_padding(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        html = '<div style="padding:12">some text</div>'
        height = _estimate_markdown_height(html)
        assert height >= 19

    def test_plain_text_no_html_tags(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        text = "A" * 120  # ~3 lines at 40 chars/line
        height = _estimate_markdown_height(text)
        assert 19 <= height <= 200

    def test_caps_at_200(self):
        from src.core.superset_client._layout_utils import _estimate_markdown_height

        text = "word " * 5000  # very long
        height = _estimate_markdown_height(text)
        assert height <= 200


class TestGenerateBannerId:
    """_generate_banner_id: chart_id -> (row_key, md_key)."""

    def test_returns_deterministic_keys(self):
        from src.core.superset_client._layout_utils import _generate_banner_id

        row_key, md_key = _generate_banner_id(42)
        assert row_key == "ROW-banner-42"
        assert md_key == "MARKDOWN-banner-42"

    def test_zero_chart_id(self):
        from src.core.superset_client._layout_utils import _generate_banner_id

        row_key, md_key = _generate_banner_id(0)
        assert row_key == "ROW-banner-0"
        assert md_key == "MARKDOWN-banner-0"


class TestInsertBannerMarkdownAtTop:
    """insert_banner_markdown_at_top: position_json + chart_id + content -> mutated dict."""

    def test_inserts_row_and_markdown_at_top(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {"GRID_ID": {"children": ["ROW-existing"]}}
        result = insert_banner_markdown_at_top(position_json, 1, "Hello")
        assert "ROW-banner-1" in result
        assert "MARKDOWN-banner-1" in result
        children = result["GRID_ID"]["children"]
        assert children[0] == "ROW-banner-1"
        assert "ROW-existing" in children

    def test_shifts_existing_items_down(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {
            "GRID_ID": {"children": ["ROW-existing"]},
            "ROW-existing": {"type": "ROW", "meta": {"y": 0}},
        }
        insert_banner_markdown_at_top(position_json, 2, "Banner")
        assert position_json["ROW-existing"]["meta"]["y"] == 2

    def test_handles_missing_grid(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {}
        result = insert_banner_markdown_at_top(position_json, 3, "Content")
        assert "ROW-banner-3" in result
        assert "MARKDOWN-banner-3" in result

    def test_content_affects_height(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {"GRID_ID": {"children": []}}
        result = insert_banner_markdown_at_top(position_json, 4, "short")
        md_meta = result["MARKDOWN-banner-4"]["meta"]
        assert md_meta["height"] >= 19
        assert md_meta["code"] == "short"

    def test_row_removed_from_grid_if_duplicate(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        # If ROW already exists in children, it should be moved to front
        position_json = {
            "GRID_ID": {"children": ["ROW-banner-5", "ROW-other"]},
            "ROW-banner-5": {"type": "ROW", "meta": {"y": 0}},
        }
        # This simulates a re-insert
        insert_banner_markdown_at_top(position_json, 5, "Updated")
        children = position_json["GRID_ID"]["children"]
        assert children[0] == "ROW-banner-5"
        assert children[1] == "ROW-other"
        assert len(children) == 2

    def test_markdown_includes_parents(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {"GRID_ID": {"children": []}}
        result = insert_banner_markdown_at_top(position_json, 6, "test")
        md = result["MARKDOWN-banner-6"]
        assert md["parents"] == ["ROOT_ID", "GRID_ID", "ROW-banner-6"]
        assert md["type"] == "MARKDOWN"

    def test_row_includes_parents(self):
        from src.core.superset_client._layout_utils import insert_banner_markdown_at_top

        position_json = {"GRID_ID": {"children": []}}
        result = insert_banner_markdown_at_top(position_json, 7, "test")
        row = result["ROW-banner-7"]
        assert row["parents"] == ["ROOT_ID", "GRID_ID"]
        assert row["type"] == "ROW"
        assert row["children"] == ["MARKDOWN-banner-7"]


class TestUpdateBannerMarkdownContent:
    """update_banner_markdown_content: position_json + key + content -> mutated dict."""

    def test_updates_content_and_height(self):
        from src.core.superset_client._layout_utils import update_banner_markdown_content

        position_json = {
            "MARKDOWN-banner-1": {
                "type": "MARKDOWN",
                "meta": {"code": "old", "height": 19},
            }
        }
        update_banner_markdown_content(position_json, "MARKDOWN-banner-1", "new content " * 20)
        meta = position_json["MARKDOWN-banner-1"]["meta"]
        assert meta["code"] == "new content " * 20
        assert meta["height"] >= 19

    def test_does_nothing_if_key_not_found(self):
        from src.core.superset_client._layout_utils import update_banner_markdown_content

        position_json = {"other": {"meta": {"code": "x"}}}
        result = update_banner_markdown_content(position_json, "MARKDOWN-banner-99", "new")
        assert result is position_json  # no crash, returns same dict

    def test_handles_missing_meta(self):
        from src.core.superset_client._layout_utils import update_banner_markdown_content

        position_json = {"MARKDOWN-banner-1": {"type": "MARKDOWN"}}
        result = update_banner_markdown_content(position_json, "MARKDOWN-banner-1", "content")
        assert result is position_json  # no crash


class TestRemoveBannerFromPosition:
    """remove_banner_from_position: position_json + chart_id -> mutated dict."""

    def test_removes_row_and_markdown(self):
        from src.core.superset_client._layout_utils import remove_banner_from_position

        position_json = {
            "GRID_ID": {"children": ["ROW-banner-1", "ROW-other"]},
            "ROW-banner-1": {"type": "ROW", "meta": {"y": 0}},
            "MARKDOWN-banner-1": {"type": "MARKDOWN", "meta": {"y": 0}},
            "ROW-other": {"type": "ROW", "meta": {"y": 2}},
        }
        result = remove_banner_from_position(position_json, 1)
        assert "ROW-banner-1" not in result
        assert "MARKDOWN-banner-1" not in result
        assert "ROW-other" in result
        assert "GRID_ID" in result
        # ROW-banner-1 removed from children list
        assert "ROW-banner-1" not in result["GRID_ID"]["children"]

    def test_shifts_remaining_items_up_when_banner_at_y0(self):
        from src.core.superset_client._layout_utils import remove_banner_from_position

        position_json = {
            "GRID_ID": {"children": ["ROW-banner-1", "ROW-other"]},
            "ROW-banner-1": {"type": "ROW", "meta": {"y": 0}},
            "MARKDOWN-banner-1": {"type": "MARKDOWN", "meta": {"y": 0}},
            "ROW-other": {"type": "ROW", "meta": {"y": 2}},
        }
        remove_banner_from_position(position_json, 1)
        assert position_json["ROW-other"]["meta"]["y"] == 0

    def test_does_not_shift_when_banner_not_at_y0(self):
        from src.core.superset_client._layout_utils import remove_banner_from_position

        position_json = {
            "GRID_ID": {"children": ["ROW-banner-1", "ROW-other"]},
            "ROW-banner-1": {"type": "ROW", "meta": {"y": 5}},
            "MARKDOWN-banner-1": {"type": "MARKDOWN", "meta": {"y": 5}},
            "ROW-other": {"type": "ROW", "meta": {"y": 2}},
        }
        remove_banner_from_position(position_json, 1)
        assert position_json["ROW-other"]["meta"]["y"] == 2

    def test_noop_when_banner_does_not_exist(self):
        from src.core.superset_client._layout_utils import remove_banner_from_position

        position_json = {"GRID_ID": {"children": ["ROW-other"]}, "ROW-other": {"meta": {"y": 0}}}
        result = remove_banner_from_position(position_json, 99)
        assert result is position_json  # no crash
        assert "ROW-other" in result
# #endregion Test.LayoutUtils
