"""Tests for render_automatic_eda_pdf — DoD: golden + edges + error path.

Self-contained: builds a synthetic TableProfile (no DuckDB) so the suite is fast
and deterministic. Verifies the cover/overview reference chapters render, that
long tables split by rows repeating the header without losing any cell text,
that an empty/None profile still yields a valid 1-page PDF, and that an
unwritable destination returns ``{path: None}`` without raising.
"""

import os
import re
import tempfile

from pypdf import PdfReader

from datascience.render_automatic_eda_pdf import render_automatic_eda_pdf
from datascience.automatic_eda.model import Chapter, DataTable, Heading, Markdown


def _profile() -> dict:
    return {
        "table": "ventas",
        "source": "/data/ventas.csv",
        "profiled_at": "2026-06-30T10:00:00+00:00",
        "n_rows": 1000,
        "n_cols": 3,
        "quality_score": 92.5,
        "key_candidates": ["id"],
        "type_breakdown": {"numeric": 2, "categorical": 1},
        "columns": [
            {"name": "id", "inferred_type": "numeric", "null_pct": 0.0,
             "null_count": 0,
             "numeric": {"mean": 500.0, "median": 500.0, "min": 1.0,
                         "max": 1000.0, "std": 288.7}},
            {"name": "precio", "inferred_type": "numeric", "null_pct": 0.01,
             "null_count": 10,
             "numeric": {"mean": 42.5, "median": 40.0, "min": 1.0,
                         "max": 100.0, "std": 12.3}},
            {"name": "categoria", "inferred_type": "categorical",
             "null_pct": 0.0, "null_count": 0,
             "categorical": {"top": [{"value": "neumaticos", "count": 500},
                                     {"value": "aceite", "count": 300}]}},
        ],
    }


def _pdf_text(path: str) -> str:
    txt = "".join((pg.extract_text() or "") for pg in PdfReader(path).pages)
    return re.sub(r"\s+", " ", txt)


def test_golden_profile_genera_pdf_portada_y_overview():
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "eda.pdf")
        res = render_automatic_eda_pdf(_profile(), out, {"title": "EDA — ventas"})
        assert res["path"] == out
        assert os.path.exists(out)
        assert res["n_pages"] >= 2  # portada + overview (1+ each).
        ids = [c["id"] for c in res["chapters"]]
        assert "portada" in ids and "overview" in ids
        # Manifest written next to the output with both chapters versioned.
        assert res["manifest_path"] and os.path.exists(res["manifest_path"])
        txt = _pdf_text(out)
        # Cover fields.
        assert "Automatic-EDA" in txt
        assert "CSV" in txt          # storage inferred from .csv source.
        assert "Calidad" in txt and "92.5" in txt
        assert "Fuente" in txt
        # Overview content: column dictionary + describe.
        assert "precio" in txt and "categoria" in txt
        assert "median" in txt


def test_edge_tabla_larga_parte_repitiendo_cabecera():
    # 60 rows over 6 wide columns: the table must split across pages and repeat
    # the header on every continuation page (headers wide enough not to wrap).
    header = ["ALPHA", "BETA", "GAMMA", "DELTA", "EPSILON", "ZETA"]
    rows = [[f"r{r}c{c}" for c in range(6)] for r in range(60)]
    ch = Chapter(id="edge", title="Edge", version="1.0.0",
                 blocks=[Heading("Tabla", 1),
                         DataTable(header=header, rows=rows)])
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "edge.pdf")
        res = render_automatic_eda_pdf([ch], out, {"write_manifest": False})
        assert res["path"] == out
        reader = PdfReader(out)
        n_pages = len(reader.pages)
        assert n_pages > 1  # table spilled to several pages.
        pages_with_header = sum(
            1 for pg in reader.pages if "ALPHA" in (pg.extract_text() or ""))
        assert pages_with_header == n_pages  # header repeated on every page.


def test_edge_celda_larga_no_se_corta():
    # A single cell with ~150 chars must wrap inside its column (the row grows),
    # never truncated: all of its words survive in the rendered PDF.
    long_cell = ("Lorem ipsum dolor sit amet consectetur adipiscing elit sed do "
                 "eiusmod tempor incididunt ut labore et dolore magna aliqua "
                 "reprehenderit voluptate")
    header = ["clave", "descripcion"]
    rows = [["k1", long_cell], ["k2", "corto"]]
    ch = Chapter(id="edge2", title="Edge2", version="1.0.0",
                 blocks=[DataTable(header=header, rows=rows)])
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "edge2.pdf")
        render_automatic_eda_pdf([ch], out, {"write_manifest": False})
        txt = _pdf_text(out)
        # Every word of the long cell present (wrapped, not truncated).
        for word in ("Lorem", "incididunt", "reprehenderit", "voluptate"):
            assert word in txt


def test_no_corta_texto_markdown():
    para = " ".join(f"palabra{i}" for i in range(120))
    ch = Chapter(id="md", title="MD", version="1.0.0",
                 blocks=[Markdown(text=para)])
    with tempfile.TemporaryDirectory() as d:
        out = os.path.join(d, "md.pdf")
        render_automatic_eda_pdf([ch], out, {"write_manifest": False})
        txt = _pdf_text(out)
        for i in (0, 60, 119):  # first, middle, last words all present.
            assert f"palabra{i}" in txt


def test_edge_profile_none_y_vacio_un_pagina():
    with tempfile.TemporaryDirectory() as d:
        for arg, name in ((None, "none"), ({}, "empty")):
            out = os.path.join(d, f"{name}.pdf")
            res = render_automatic_eda_pdf(arg, out, {"write_manifest": False})
            assert res["path"] == out
            assert os.path.exists(out)
            assert res["n_pages"] == 1


def test_error_path_directorio_no_escribible_no_revienta():
    res = render_automatic_eda_pdf(_profile(), "/proc/nope/x.pdf",
                                   {"write_manifest": False})
    assert res["path"] is None
    assert res["n_pages"] == 0
    assert res["note"]
