"""Tests para metabase_validate_card_payload y metabase_validate_dashboard_payload."""

import sys

sys.path.insert(0, "/home/lucas/fn_registry/python/functions")

from metabase.validation import (
    metabase_validate_card_payload,
    metabase_validate_dashboard_payload,
)


# ---------------------------------------------------------------------------
# metabase_validate_card_payload
# ---------------------------------------------------------------------------

def _base_card() -> dict:
    return {
        "name": "Revenue by Month",
        "display": "line",
        "dataset_query": {
            "database": 1,
            "type": "native",
            "native": {"query": "SELECT 1"},
        },
    }


def test_card_valido_retorna_lista_vacia():
    issues = metabase_validate_card_payload(_base_card())
    assert issues == [], f"Se esperaba lista vacia, got: {issues}"


def test_card_display_invalido():
    payload = _base_card()
    payload["display"] = "foobar"
    issues = metabase_validate_card_payload(payload)
    assert any("display" in i and "foobar" in i for i in issues), issues


def test_card_display_ausente():
    payload = _base_card()
    del payload["display"]
    issues = metabase_validate_card_payload(payload)
    assert any("display" in i and "ausente" in i for i in issues), issues


def test_card_name_ausente():
    payload = _base_card()
    del payload["name"]
    issues = metabase_validate_card_payload(payload)
    assert any("name" in i and "ausente" in i for i in issues), issues


def test_card_name_vacio():
    payload = _base_card()
    payload["name"] = "   "
    issues = metabase_validate_card_payload(payload)
    assert any("name" in i for i in issues), issues


def test_card_dataset_query_ausente():
    payload = _base_card()
    del payload["dataset_query"]
    issues = metabase_validate_card_payload(payload)
    assert any("dataset_query" in i and "ausente" in i for i in issues), issues


def test_card_dataset_query_sin_database():
    payload = _base_card()
    del payload["dataset_query"]["database"]
    issues = metabase_validate_card_payload(payload)
    assert any("database" in i for i in issues), issues


def test_card_nativa_sin_sql():
    payload = _base_card()
    payload["dataset_query"]["native"]["query"] = ""
    issues = metabase_validate_card_payload(payload)
    assert any("SQL" in i or "native" in i for i in issues), issues


def test_card_nativa_mbql5():
    """Acepta SQL en stages[0].native (formato MBQL5)."""
    payload = {
        "name": "MBQL5 card",
        "display": "table",
        "dataset_query": {
            "database": 2,
            "stages": [{"native": "SELECT 1"}],
        },
    }
    issues = metabase_validate_card_payload(payload)
    assert issues == [], f"Se esperaba lista vacia, got: {issues}"


def test_card_type_invalido():
    payload = _base_card()
    payload["type"] = "unknown_type"
    issues = metabase_validate_card_payload(payload)
    assert any("type" in i and "unknown_type" in i for i in issues), issues


def test_card_type_valido():
    for t in ("question", "model", "metric"):
        payload = _base_card()
        payload["type"] = t
        issues = metabase_validate_card_payload(payload)
        assert issues == [], f"type={t!r} no deberia dar issues: {issues}"


def test_card_visualization_settings_no_dict():
    payload = _base_card()
    payload["visualization_settings"] = "no es un dict"
    issues = metabase_validate_card_payload(payload)
    assert any("visualization_settings" in i for i in issues), issues


def test_card_parameters_no_list():
    payload = _base_card()
    payload["parameters"] = {"not": "a list"}
    issues = metabase_validate_card_payload(payload)
    assert any("parameters" in i for i in issues), issues


def test_card_archived_no_bool():
    payload = _base_card()
    payload["archived"] = "yes"
    issues = metabase_validate_card_payload(payload)
    assert any("archived" in i for i in issues), issues


def test_card_acumula_multiples_errores():
    """Un payload con varios errores debe retornar todos los issues, no solo el primero."""
    payload = {
        "display": "invalid_display",
        "dataset_query": "not a dict",
        "archived": "yes",
    }
    issues = metabase_validate_card_payload(payload)
    assert len(issues) >= 3, f"Se esperaban >= 3 issues, got {len(issues)}: {issues}"


# ---------------------------------------------------------------------------
# metabase_validate_dashboard_payload
# ---------------------------------------------------------------------------

def _base_dashboard() -> dict:
    return {"name": "My Dashboard"}


def test_dashboard_valido_sin_dashcards():
    issues = metabase_validate_dashboard_payload(_base_dashboard(), known_card_ids=set())
    assert issues == [], issues


def test_dashboard_valido_con_dashcards():
    payload = {
        "name": "KPIs",
        "dashcards": [
            {"card_id": 1, "row": 0, "col": 0, "size_x": 6, "size_y": 4},
            {"card_id": 2, "row": 0, "col": 6, "size_x": 6, "size_y": 4},
        ],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1, 2})
    assert issues == [], issues


def test_dashboard_card_id_desconocido():
    payload = {
        "name": "Dashboard",
        "dashcards": [{"card_id": 999, "row": 0, "col": 0, "size_x": 6, "size_y": 4}],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1, 2})
    assert any("999" in i for i in issues), issues


def test_dashboard_card_virtual_null_permitido():
    """card_id null = dashcard virtual (texto/heading), siempre permitido."""
    payload = {
        "name": "Dashboard",
        "dashcards": [{"card_id": None, "row": 0, "col": 0, "size_x": 6, "size_y": 2}],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids=set())
    assert issues == [], issues


def test_dashboard_dashcards_solapadas():
    payload = {
        "name": "Dashboard",
        "dashcards": [
            {"card_id": 1, "row": 0, "col": 0, "size_x": 6, "size_y": 4},
            {"card_id": 2, "row": 2, "col": 2, "size_x": 4, "size_y": 4},
        ],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1, 2})
    assert any("solapan" in i for i in issues), issues


def test_dashboard_dashcards_adyacentes_no_solapan():
    """Dos dashcards que se tocan en el borde NO solapan."""
    payload = {
        "name": "Dashboard",
        "dashcards": [
            {"card_id": 1, "row": 0, "col": 0, "size_x": 6, "size_y": 4},
            {"card_id": 2, "row": 0, "col": 6, "size_x": 6, "size_y": 4},
        ],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1, 2})
    assert not any("solapan" in i for i in issues), issues


def test_dashboard_col_fuera_de_bounds():
    payload = {
        "name": "Dashboard",
        "dashcards": [{"card_id": 1, "row": 0, "col": 25, "size_x": 1, "size_y": 1}],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1})
    assert any("col" in i for i in issues), issues


def test_dashboard_col_mas_size_x_excede_grid():
    payload = {
        "name": "Dashboard",
        "dashcards": [{"card_id": 1, "row": 0, "col": 20, "size_x": 6, "size_y": 4}],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1})
    assert any("24" in i for i in issues), issues


def test_dashboard_size_y_fuera_de_bounds():
    payload = {
        "name": "Dashboard",
        "dashcards": [{"card_id": 1, "row": 0, "col": 0, "size_x": 6, "size_y": 0}],
    }
    issues = metabase_validate_dashboard_payload(payload, known_card_ids={1})
    assert any("size_y" in i for i in issues), issues


def test_dashboard_name_ausente():
    issues = metabase_validate_dashboard_payload({}, known_card_ids=set())
    assert any("name" in i and "ausente" in i for i in issues), issues


def test_dashboard_tabs_invalidos():
    payload = {"name": "Dashboard", "tabs": [{"name": "Tab1"}]}  # falta id
    issues = metabase_validate_dashboard_payload(payload, known_card_ids=set())
    assert any("id" in i for i in issues), issues


def test_dashboard_parameters_no_list():
    payload = {"name": "Dashboard", "parameters": "not a list"}
    issues = metabase_validate_dashboard_payload(payload, known_card_ids=set())
    assert any("parameters" in i for i in issues), issues


# ---------------------------------------------------------------------------
# metabase_validate_document_payload
# ---------------------------------------------------------------------------

from metabase.validation import metabase_validate_document_payload


def _base_doc(content):
    return {"name": "Notas", "document": {"type": "doc", "content": content}}


def test_document_valido_minimo():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "paragraph", "content": [{"type": "text", "text": "hola"}]}
    ]))
    assert issues == [], issues


def test_document_name_ausente():
    issues = metabase_validate_document_payload({"document": {"type": "doc", "content": []}})
    assert any("name" in i and "ausente" in i for i in issues), issues


def test_document_nodo_desconocido_callout():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "callout", "content": [{"type": "paragraph", "content": [{"type": "text", "text": "x"}]}]}
    ]))
    assert any("callout" in i and "no soportado" in i for i in issues), issues


def test_document_nodo_desconocido_taskList():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "taskList", "content": []}
    ]))
    assert any("taskList" in i for i in issues), issues


def test_document_mark_desconocido_underline():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "paragraph", "content": [
            {"type": "text", "marks": [{"type": "underline"}], "text": "x"}
        ]}
    ]))
    assert any("underline" in i and "no soportado" in i for i in issues), issues


def test_document_heading_level_invalido():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "heading", "attrs": {"level": 9}, "content": [{"type": "text", "text": "x"}]}
    ]))
    assert any("level" in i for i in issues), issues


def test_document_cardEmbed_sin_id_ni_slug():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "cardEmbed", "attrs": {}}
    ]))
    assert any("cardEmbed" in i and "id" in i for i in issues), issues


def test_document_cardEmbed_con_id_valido():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "cardEmbed", "attrs": {"id": 42}}
    ]))
    assert issues == [], issues


def test_document_cardEmbed_slug_desconocido():
    issues = metabase_validate_document_payload(
        _base_doc([{"type": "cardEmbed", "attrs": {"card": "inventado"}}]),
        known_card_slugs={"real_one", "real_two"},
    )
    assert any("inventado" in i for i in issues), issues


def test_document_flexContainer_demasiados_hijos():
    children = [{"type": "cardEmbed", "attrs": {"id": 1}} for _ in range(4)]
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "flexContainer", "attrs": {"columnWidths": [25, 25, 25, 25]}, "content": children}
    ]))
    assert any("1-3" in i for i in issues), issues


def test_document_flexContainer_hijo_invalido():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "flexContainer", "attrs": {"columnWidths": [100]}, "content": [
            {"type": "paragraph", "content": [{"type": "text", "text": "x"}]}
        ]}
    ]))
    assert any("flexContainer solo acepta" in i for i in issues), issues


def test_document_flexContainer_columnWidths_mismatch():
    issues = metabase_validate_document_payload(_base_doc([
        {"type": "flexContainer", "attrs": {"columnWidths": [50, 50]}, "content": [
            {"type": "cardEmbed", "attrs": {"id": 1}}
        ]}
    ]))
    assert any("columnWidths" in i for i in issues), issues


def test_document_vacio_string_es_valido():
    issues = metabase_validate_document_payload({"name": "vacio", "document": ""})
    assert issues == [], issues


def test_document_kitchen_sink_valido():
    """Simula el kitchen_sink real y debe pasar sin issues."""
    content = [
        {"type": "heading", "attrs": {"level": 1}, "content": [{"type": "text", "text": "T"}]},
        {"type": "paragraph", "content": [
            {"type": "text", "text": "a "},
            {"type": "text", "marks": [{"type": "bold"}], "text": "b"},
            {"type": "text", "marks": [{"type": "link", "attrs": {"href": "https://x"}}], "text": "l"},
        ]},
        {"type": "bulletList", "content": [
            {"type": "listItem", "content": [
                {"type": "paragraph", "content": [{"type": "text", "text": "i"}]}
            ]}
        ]},
        {"type": "blockquote", "content": [
            {"type": "paragraph", "content": [{"type": "text", "text": "q"}]}
        ]},
        {"type": "codeBlock", "attrs": {"language": "py"}, "content": [{"type": "text", "text": "x=1"}]},
        {"type": "horizontalRule"},
        {"type": "cardEmbed", "attrs": {"id": 1}},
        {"type": "flexContainer", "attrs": {"columnWidths": [50, 50]}, "content": [
            {"type": "cardEmbed", "attrs": {"id": 1}},
            {"type": "cardEmbed", "attrs": {"id": 2}},
        ]},
    ]
    issues = metabase_validate_document_payload(_base_doc(content))
    assert issues == [], issues
