"""Smoke tests: every page renders without exception in EN and ES.

The cheapest, highest-value GUI tests in the project. They catch:

- Page-level Python errors (import failures, syntax errors that
  ``ast.parse`` misses because they're runtime, e.g., a missing
  attribute on a module).
- i18n pack key drift (a string that used to render in EN now renders
  literally as ``"chrome.language_label"`` because someone renamed the
  key in en.json but forgot es.json or the call site).
- Streamlit API churn that breaks ``set_page_config`` /
  ``hide_streamlit_chrome`` on a single page.

What they don't cover: user interactions. Those live in the workflow
tests.
"""

from __future__ import annotations

import pytest

from .conftest import collected_text, with_language


# Every page that ships in the sidebar nav. Slugs match the filenames
# under ``src/gui/pages/`` so failures point at a real file.
PAGE_SLUGS = [
    "1_Deduplicator",
    "2_Text_Cleaner",
    "3_Format_Standardizer",
    "4_Missing_Values",
    "5_Column_Mapper",
    "6_Outlier_Detector",
    "7_Multi_File_Merger",
    "8_Validator_Reporter",
    "9_Pipeline_Runner",
    "10_PDF_Extractor",
    "11_Reconciler",
    "99_Close",
]


# Substrings that must appear on each page for each language.
#
# v1.6 coverage reality (also documented in docs/USER-GUIDE.md §3.4):
# only the home page, the Close page, and the shared chrome /
# components ship Spanish strings. Per-tool page bodies are still
# hard-coded English in both modes — translating them is tracked as a
# follow-up. The substrings below reflect that reality: a page that
# isn't translated yet asserts the same English substring under both
# languages. The fact that the page *renders at all* in 'es' is still
# the value of the smoke test.
#
# When a page gains real Spanish translation, flip its 'es' entry to
# the localized substring — the test surface stays the same.
EXPECTED_SUBSTRINGS: dict[str, dict[str, str]] = {
    "1_Deduplicator":        {"en": "Find Duplicates",   "es": "Buscar duplicados"},
    "2_Text_Cleaner":        {"en": "Clean Text",        "es": "Limpiar texto"},
    "3_Format_Standardizer": {"en": "Standardize",       "es": "Estandarizar"},
    "4_Missing_Values":      {"en": "Fix Missing",       "es": "Corregir valores"},
    "5_Column_Mapper":       {"en": "Map Columns",       "es": "Mapear columnas"},
    "6_Outlier_Detector":    {"en": "Unusual",           "es": "atípicos"},
    "7_Multi_File_Merger":   {"en": "Combine Files",     "es": "Combinar archivos"},
    "8_Validator_Reporter":  {"en": "Quality Check",     "es": "Verificación de calidad"},
    "9_Pipeline_Runner":     {"en": "Automated",         "es": "Flujos automatizados"},
    # PDF Extractor + Reconciler page titles are now translated in
    # both packs (``tools.<id>.page_title``). Their hero copy diverges
    # by language, so the smoke test pins the localized substring.
    "10_PDF_Extractor":      {"en": "PDF to CSV",        "es": "PDF a CSV"},
    "11_Reconciler":         {"en": "Reconcile",         "es": "Reconciliar"},
    "99_Close":              {"en": "Shutting down",     "es": "Cerrando"},
}


class TestHomePageRenders:
    """Pin the home hero in both languages.

    Since the v3 brand refresh the title is the literal wordmark
    ("UNALOGIX DataTools") in both packs; the localized tagline is
    what shifts between en and es. We assert against the tagline
    string, which lives in ``home.caption`` of each pack.
    """

    @pytest.mark.parametrize("lang,expected", [
        ("en", "Clean. Normalize. Transform."),
        ("es", "Limpia. Normaliza. Transforma."),
    ])
    def test_home_renders_in_language(self, home_app, lang, expected):
        with_language(home_app, lang)
        home_app.run()
        assert home_app.exception is None or home_app.exception == [], (
            f"home page raised: {home_app.exception}"
        )
        assert expected in collected_text(home_app)

    def test_home_renders_privacy_pill_in_es(self, home_app):
        # The footer caption is rendered via a component-iframe so
        # ``collected_text`` can't see it. The privacy pill on the
        # home header IS visible to AppTest and carries the same
        # locality story, so we pin that instead.
        with_language(home_app, "es")
        home_app.run()
        text = collected_text(home_app)
        assert "Se ejecuta 100% en local" in text

class TestEveryPageRenders:
    """Parametrize over (page, language). Failure tells you exactly which
    page + which language broke."""

    @pytest.mark.parametrize("slug", PAGE_SLUGS)
    @pytest.mark.parametrize("lang", ["en", "es"])
    def test_renders_without_exception(self, app_factory, slug, lang):
        app = app_factory(slug)
        with_language(app, lang)
        app.run()
        # AppTest exposes ``exception`` as a list of element-wrapped
        # exceptions (empty when no error fired).
        assert not app.exception, (
            f"page {slug!r} raised in language {lang!r}: {app.exception}"
        )

    @pytest.mark.parametrize("slug", PAGE_SLUGS)
    @pytest.mark.parametrize("lang", ["en", "es"])
    def test_expected_substring_present(self, app_factory, slug, lang):
        app = app_factory(slug)
        with_language(app, lang)
        app.run()
        needle = EXPECTED_SUBSTRINGS[slug][lang]
        text = collected_text(app)
        assert needle in text, (
            f"page {slug!r} ({lang!r}) missing expected substring "
            f"{needle!r}\nGot:\n{text[:500]}…"
        )


class TestPageHasLanguageSelector:
    """Every page that calls ``hide_streamlit_chrome`` should mount the
    sidebar language selector. This is the only place the picker is
    rendered — if the chrome helper stops calling it, the test fails."""

    @pytest.mark.parametrize("slug", PAGE_SLUGS)
    def test_sidebar_selectbox_present(self, app_factory, slug):
        app = app_factory(slug)
        app.run()
        # The selector is the only sidebar selectbox we ship today; if
        # a page adds another the test should be loosened to "at least
        # one selectbox with the language label."
        assert len(app.sidebar.selectbox) >= 1, (
            f"page {slug!r} has no sidebar selectbox — "
            f"hide_streamlit_chrome() should have mounted the language "
            f"selector."
        )
