"""Tests for render_automatic_eda_markdown — DoD: golden + edge + profile path.

Self-contained synthetic blocks (no DuckDB). Verifies every block kind serializes
to Markdown (heading, markdown with glossary+bold, kv/data tables, a figure whose
histogram bars become a data table, caption, note, group, glossary entry), that a
leading level-1 heading equal to the chapter title is omitted, that an empty
document degrades to a valid minimal Markdown without raising, and that passing a
minimal TableProfile builds chapters and writes the file.
"""

import os
import tempfile

from datascience.render_automatic_eda_markdown import render_automatic_eda_markdown
from datascience.automatic_eda.model import (
    Caption, Chapter, DataTable, Figure, GlossaryEntry, Group, Heading, KVTable,
    Markdown, Note,
)


def _hist_fig():
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots()
    ax.hist([1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5], bins=5)
    return fig


def _chapters() -> list:
    blocks = [
        Heading("Demo", 1),                       # == chapter title -> omitted.
        Heading("Seccion dos", 2),                # -> ####
        Markdown("Texto con [[term:ent]]entropia[[/term]] y **bold** aqui."),
        KVTable(rows=[("Filas", 1000), ("Columnas", 5)], title="Resumen"),
        DataTable(header=["col", "valor"],
                  rows=[["alpha", "111"], ["beta", "222"], ["gamma", "333"]],
                  title="Datos", note="nota inferior"),
        Figure(make=_hist_fig, caption="Histograma demo"),
        Caption("pie de figura"),
        Note("una nota aparte"),
        Group(title="Grupo X", blocks=[Markdown("dentro del grupo")]),
        GlossaryEntry(key="ent", label="Entropia",
                      definition="Medida de incertidumbre."),
    ]
    return [Chapter(id="demo", title="Demo", version="1.0.0", blocks=blocks)]


def _read(path: str) -> str:
    with open(path, "r", encoding="utf-8") as fh:
        return fh.read()


def test_golden_bloques_sinteticos_serializa_todo_a_markdown():
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "demo.md")
        res = render_automatic_eda_markdown(
            _chapters(), out,
            {"title": "EDA Demo",
             "ctx": {"dataset_name": "Demo", "n_rows": 12, "n_cols": 2}})
        assert res["path"] == out
        assert os.path.exists(out)
        assert res["n_chars"] > 0
        assert res["chapters"] == [{"id": "demo", "version": "1.0.0"}]

        content = _read(out)
        # Document structure.
        assert content.startswith("# ")
        assert "## Índice" in content
        # A Markdown table is present (header + separator row).
        assert "| " in content and "| --- " in content
        # DataTable values are all dumped.
        for v in ("alpha", "111", "beta", "222", "gamma", "333"):
            assert v in content
        # Glossary markers stripped, bold kept.
        assert "[[term" not in content
        assert "[[/term]]" not in content
        assert "**bold**" in content
        assert "entropia" in content  # visible glossary text preserved.
        # Figure histogram bars became a data table.
        assert "| Desde | Hasta | Frecuencia |" in content
        # Glossary entry rendered as a level-3 heading.
        assert "### Entropia" in content
        # Level-2 heading -> ####.
        assert "#### Seccion dos" in content
        # Leading level-1 heading equal to the title was omitted.
        assert "### Demo" not in content
        # Group title rendered.
        assert "### Grupo X" in content


def _hist_fig_with_span():
    """Histogram with a wide ``axvspan`` (±1σ band) over it.

    Reproduces the num_distr figure shape: matplotlib keeps the span as a lone
    Rectangle in ``ax.patches`` alongside the bin bars; it must NOT leak into the
    extracted bins table as a fake bin (it is ~5x wider than a bin)."""
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    fig, ax = plt.subplots()
    data = [1, 1, 2, 2, 2, 3, 4, 4, 5, 5, 5, 5]
    ax.hist(data, bins=5)
    ax.axvspan(2.0, 4.0, alpha=0.2)   # mean±σ band — a wide stray rectangle.
    return fig


def test_figura_descarta_axvspan_de_la_tabla_de_bins():
    """The ±1σ band rectangle must not appear as a row in the bins table."""
    blocks = [Figure(make=_hist_fig_with_span, caption="Hist con banda")]
    chapters = [Chapter(id="f", title="Fig", version="1.0.0", blocks=blocks)]
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "fig.md")
        render_automatic_eda_markdown(chapters, out, {"title": "T"})
        content = _read(out)
        assert "| Desde | Hasta | Frecuencia |" in content
        # Extract the rows of the bins table: lines between the header/separator
        # and the next blank line.
        lines = content.splitlines()
        hi = next(i for i, ln in enumerate(lines)
                  if ln.startswith("| Desde | Hasta | Frecuencia |"))
        rows = []
        for ln in lines[hi + 2:]:           # skip header + separator
            if not ln.startswith("|"):
                break
            rows.append(ln)
        # 5 histogram bins, no extra wide span row.
        assert len(rows) == 5, rows
        # No row spans a width of ~2.0 (the axvspan from x=2 to x=4).
        for ln in rows:
            cells = [c.strip() for c in ln.strip("|").split("|")]
            lo, hi_v = float(cells[0]), float(cells[1])
            assert (hi_v - lo) < 1.5, f"wide span leaked: {ln}"


def test_edge_documento_vacio_no_revienta():
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "empty.md")
        res = render_automatic_eda_markdown([], out, {})
        assert res["path"] == out
        assert os.path.exists(out)
        assert res["chapters"] == []
        content = _read(out)
        assert "documento vacío" in content
        assert content.startswith("# ")


def test_profile_path_construye_capitulos_y_escribe():
    profile = {
        "table": "mini",
        "source": "/data/mini.csv",
        "n_rows": 10,
        "n_cols": 1,
        "quality_score": 88.0,
        "columns": [
            {"name": "x", "inferred_type": "numeric", "null_pct": 0.0,
             "null_count": 0,
             "numeric": {"mean": 1.0, "median": 1.0, "min": 0.0, "max": 2.0,
                         "std": 0.5}},
        ],
    }
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "mini.md")
        res = render_automatic_eda_markdown(
            profile, out, {"title": "Mini", "ctx": {"dataset_name": "Mini"}})
        assert res["path"] == out  # not None — no exception, file written.
        assert os.path.exists(out)
        assert res["n_chars"] > 0
