"""
Dos controles que decían una cosa y hacían otra (RT-07).

El contador del menú aterrizaba en la lista entera: se hacía clic en un «1» y
el uno quedaba en algún lado de la página. Y el botón del estado vacío de
Sitemaps era un ancla que empujaba la pantalla **hacia arriba**, a un
formulario que ya estaba a la vista, sin dejar a nadie en condiciones de
escribir.

Se comprueban sobre el archivo del cliente y no sobre una respuesta porque no
hay servidor en el medio: el destino del menú y la acción del vacío se deciden
enteros en el navegador. La suite no tiene con qué ejecutar TSX, así que se
guarda el contrato del archivo, igual que `test_routes.py` guarda la unión de
`RouteName`.
"""

import re
from pathlib import Path

from django.conf import settings

FRONTEND = Path(settings.BASE_DIR) / 'frontend'
SIDEBAR_TSX = FRONTEND / 'components' / 'app-sidebar.tsx'
SITEMAPS_TSX = FRONTEND / 'pages' / 'Sitemaps' / 'Index.tsx'


def _without_comments(source: str) -> str:
    """
    Saca lo que se explica para dejar lo que se ejecuta.

    El `(?<!:)` es lo que impide que `https://…` se lea como el principio de un
    comentario y se coma media línea de código.
    """
    return re.sub(r'/\*[\s\S]*?\*/|(?<!:)//[^\n]*', '', source)


def test_the_bell_lands_on_the_notices_it_counts():
    """
    El servidor ya dejó el recorte listo para que el menú lo use.

    «Sin leer» no es un filtro más de la tabla —`apps/notifications/views.py` lo
    dice y por eso lo saca de `NOTIFICATIONS` y lo mete a mano en la dirección—:
    es otra vista de lo mismo, y la que trae a la persona hasta acá.
    """
    source = SIDEBAR_TSX.read_text(encoding='utf-8')

    assert 'unread=1' in source, (
        'La entrada de Notificaciones tiene que llevar el recorte en la dirección. '
        'Sin `?unread=1`, el badge dice «1» y el enlace deposita en la lista completa.'
    )


def test_with_nothing_unread_the_bell_goes_back_to_the_whole_list():
    """
    Sin nada sin leer no hay recorte que hacer.

    Mandar igual a `?unread=1` dejaría a la persona mirando un vacío filtrado
    —«ningún aviso coincide»— en vez de su historial, que es lo único que queda
    para mirar cuando no hay pendientes.
    """
    source = SIDEBAR_TSX.read_text(encoding='utf-8')

    assert re.search(r'unread\s*>\s*0\s*\?[\s\S]{0,160}?unread=1', source), (
        'El `?unread=1` tiene que estar condicionado a que haya algo sin leer.'
    )


def test_the_menu_offers_a_single_door_to_googles_side():
    """
    El menú ofrecía «Recorrido guiado» y «Conexión» como hermanas, sin decir en
    qué se diferencian, y quien no lo sabe elige mal: las dos llevaban a
    pantallas que dibujaban los mismos pasos.

    Lo que se sacó no es el recorrido —conserva su dirección, su progreso y su
    comprobación por paso, y se llega desde adentro de Conexión— sino la
    **elección** entre dos rótulos que no se explicaban. Se mira el código sin
    los comentarios porque el que defiende la decisión sigue nombrando el
    recorrido, y tiene que seguir haciéndolo.

    El grupo pasó a ser el de la herramienta entera cuando el producto dejó de
    ser una sola herramienta: lo que se defiende no es cómo se llama el grupo
    sino que el recorrido no vuelva a aparecer como una entrada más al lado de
    la conexión.

    Se leen **todas** las listas de entradas y no una con un nombre fijo: el
    grupo se reparte en varias constantes desde que las pantallas del sitio se
    arman con su identificador, y atarse a un nombre haría que este test se
    rompa por una reorganización y —peor— que deje de mirar una lista nueva.
    """
    entries = _nav_entries()

    assert entries, 'Desaparecieron las entradas del menú.'
    assert '"settings"' in entries, 'Falta la puerta a la conexión con Google.'
    assert '"onboarding"' not in entries, (
        'El recorrido volvió al menú al lado de la conexión. Con dos rótulos que no dicen '
        'en qué se diferencian, la elección la termina haciendo el azar.'
    )


def test_the_menu_does_not_offer_a_list_of_domains():
    """
    La interfaz trabaja contra **un** sitio, así que un listado de varios es un
    plano de navegación de más.

    La pantalla no se borró y su dirección sigue respondiendo: lo que se defiende
    acá es que no vuelva al menú sin que alguien lo decida. El día que la cuenta
    necesite más de uno, se agrega la entrada y este test se da vuelta.
    """
    assert '"domains"' not in _nav_entries(), (
        'El listado de dominios volvió al menú. La interfaz admite un solo sitio: '
        'un listado de varios ofrece una elección que no existe.'
    )


def test_the_site_screens_are_not_drawn_without_a_site():
    """
    Cobertura, sitemaps, lotes y los ajustes cuelgan del identificador del sitio.

    Sin sitio conectado esas direcciones no se pueden armar, así que no hay
    adónde llevar. No se ofrecen apagadas: no existen (RT-07), y lo único que
    queda a la vista es la conexión, que es donde hay que ir.
    """
    source = _without_comments(SIDEBAR_TSX.read_text(encoding='utf-8'))
    guard = re.search(r'if \(!siteId\) return \[([\s\S]*?)\]', source)

    assert guard, 'Se perdió la guarda que arma el menú sin sitio conectado.'
    assert 'SITE' not in guard.group(1), (
        'Las pantallas del sitio se dibujan sin sitio conectado: sus direcciones cuelgan de '
        'un identificador que todavía no existe.'
    )


def _nav_entries() -> str:
    """Todas las listas de entradas del menú, en un solo texto y sin comentarios."""
    source = _without_comments(SIDEBAR_TSX.read_text(encoding='utf-8'))
    return '\n'.join(re.findall(r'NavEntry\[\] = \[([\s\S]*?)\n\]', source))


def test_the_empty_state_of_sitemaps_does_not_offer_an_anchor():
    """
    Se mira el código sin los comentarios a propósito.

    El comentario que explica el arreglo cita el ancla vieja, que es como tiene
    que ser: sin la forma anterior escrita, la próxima persona la vuelve a
    escribir. Lo que no puede haber es un ancla de verdad.
    """
    source = _without_comments(SITEMAPS_TSX.read_text(encoding='utf-8'))

    assert not re.search(r'href=[\'"]#', source), (
        'El vacío ofrecía «Registrar el primero» con un `<a href="#location">`: un ancla '
        'que salta hacia arriba, a un formulario que ya estaba a la vista, y deja el foco '
        'donde estaba.'
    )


def test_the_empty_state_of_sitemaps_opens_the_registration_dialog():
    source = SITEMAPS_TSX.read_text(encoding='utf-8')

    assert 'NEW_SITEMAP_PARAM' in source and '<FormDialog' in source, (
        'La acción del vacío tiene que abrir el formulario breve de registro, no devolver '
        'el formulario permanente a la vista.'
    )
