"""Tests para whatsapp_send_image.

whatsapp_send_image compone whatsapp_open_chat con tres primitivas CDP (cdp_eval,
cdp_click_xy, cdp_set_file_input) y `whatsapp_send_message` (para el caption de
seguimiento), y requiere un Chrome vivo. Aqui se mockean todas con monkeypatch sobre el
modulo `browser.whatsapp_send_image` (donde quedan ligados los nombres por el
`from browser.X import Y`), de modo que NO hace falta Chrome.

El fake de cdp_eval distingue cada expresion por un marcador de comentario JS embebido en
ella (`/*ADJUNTAR*/`, `/*ADJEXP*/`, `/*PREVIEW*/`, `/*SEND*/`, `/*LASTIMG*/`, `/*LABEL*/`).
El estado simula el ciclo real: el menu Adjuntar arranca cerrado y se abre tras un click;
tras pulsar enviar (/*SEND*/) la bandeja se vacia (/*PREVIEW*/ -> 0) y la ultima fila pasa a
ser una imagen (/*LASTIMG*/ -> True).
"""

import json
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

import browser.whatsapp_send_image as wsi  # noqa: E402
from browser.whatsapp_send_image import whatsapp_send_image  # noqa: E402

# Imagen real para pasar la validacion de existencia (este propio archivo de test).
_IMG = os.path.abspath(__file__)


class _Spy:
    def __init__(self, ret=None):
        self.calls = []
        self.ret = ret if ret is not None else {"ok": True}

    def __call__(self, *args, **kwargs):
        self.calls.append((args, kwargs))
        return self.ret


def _make_eval(label="Escribir un mensaje para el grupo NOTAS WASAP", state=None):
    state = state if state is not None else {}

    def fake(expr, *, port=9222, target_url_substr=""):
        if "/*ADJUNTAR*/" in expr:
            return {"ok": True, "value": json.dumps({"x": 575, "y": 589}), "error": ""}
        if "/*ADJEXP*/" in expr:
            n = state.get("adjexp_n", 0)
            state["adjexp_n"] = n + 1
            return {"ok": True, "value": ("false" if n == 0 else "true"), "error": ""}
        if "/*SEND*/" in expr:
            state["after_send"] = True
            return {"ok": True, "value": json.dumps({"x": 1136, "y": 578}), "error": ""}
        if "/*PREVIEW*/" in expr:
            return {"ok": True, "value": 0 if state.get("after_send") else 1, "error": ""}
        if "/*LASTIMG*/" in expr:
            return {"ok": True, "value": bool(state.get("after_send")), "error": ""}
        if "/*LABEL*/" in expr:
            return {"ok": True, "value": label, "error": ""}
        return {"ok": True, "value": None, "error": ""}

    return fake


def _patch_common(monkeypatch, *, eval_fn, set_ret={"ok": True}, open_ret=None,
                  send_msg_ret={"sent": True}):
    open_spy = _Spy(ret=open_ret if open_ret is not None else {"opened": True, "name": "x"})
    click_spy = _Spy(ret={"ok": True})
    set_spy = _Spy(ret=set_ret)
    sendmsg_spy = _Spy(ret=send_msg_ret)
    monkeypatch.setattr(wsi, "whatsapp_open_chat", open_spy)
    monkeypatch.setattr(wsi, "cdp_eval", eval_fn)
    monkeypatch.setattr(wsi, "cdp_click_xy", click_spy)
    monkeypatch.setattr(wsi, "cdp_set_file_input", set_spy)
    monkeypatch.setattr(wsi, "whatsapp_send_message", sendmsg_spy)
    monkeypatch.setattr(wsi.time, "sleep", lambda *a, **k: None)
    return open_spy, click_spy, set_spy, sendmsg_spy


def test_golden_envia_imagen_y_caption_de_seguimiento(monkeypatch):
    cap = "item icon: potion"
    state = {}
    open_spy, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch, eval_fn=_make_eval(state=state))

    res = whatsapp_send_image("NOTAS WASAP", _IMG, caption=cap,
                              port=9222, target_url_substr="whatsapp")

    assert res["sent"] is True and res["ok"] is True
    assert res["caption_sent"] is True
    assert res["recipient"] == "NOTAS WASAP"
    assert res["image"] == _IMG
    assert res["caption"] == cap
    assert res["error"] == ""
    # Se adjunto la imagen (ruta absoluta) por setFileInputFiles, una sola vez.
    assert len(set_spy.calls) == 1
    assert set_spy.calls[0][0][0] == 'input[type="file"]'
    assert set_spy.calls[0][0][1] == _IMG
    # Dos clicks reales: abrir Adjuntar (menu cerrado al inicio) y Enviar.
    assert len(click_spy.calls) == 2
    # El caption viaja como mensaje de texto de seguimiento, open_first=False.
    assert len(sendmsg_spy.calls) == 1
    assert sendmsg_spy.calls[0][0][0] == "NOTAS WASAP"
    assert sendmsg_spy.calls[0][0][1] == cap
    assert sendmsg_spy.calls[0][1].get("open_first") is False


def test_envia_sin_caption_no_manda_texto(monkeypatch):
    state = {}
    _, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch, eval_fn=_make_eval(state=state))

    res = whatsapp_send_image("NOTAS WASAP", _IMG, caption="",
                              port=9222, target_url_substr="whatsapp")

    assert res["sent"] is True
    assert res["caption_sent"] is False
    # Sin caption: NO se manda mensaje de texto de seguimiento.
    assert len(sendmsg_spy.calls) == 0
    assert len(set_spy.calls) == 1


def test_edge_imagen_no_existe_error_sin_abrir(monkeypatch):
    open_spy, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch, eval_fn=_make_eval())

    res = whatsapp_send_image("NOTAS WASAP", "/no/existe/foo.png",
                              port=9222, target_url_substr="whatsapp")

    assert res["sent"] is False and res["ok"] is False
    assert "no encontrada" in res["error"]
    # Ni siquiera se intento abrir el chat ni adjuntar.
    assert len(open_spy.calls) == 0
    assert len(set_spy.calls) == 0


def test_edge_open_fallido_error_sin_adjuntar(monkeypatch):
    open_spy, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch, eval_fn=_make_eval(),
        open_ret={"opened": False, "name": "x",
                  "reason": "chat no encontrado en la lista (no cargado o nombre inexacto)"})

    res = whatsapp_send_image("Inexistente", _IMG,
                              port=9222, target_url_substr="whatsapp")

    assert res["sent"] is False
    assert "no encontrado" in res["error"]
    # No se adjunto ni se hizo click cuando el chat no abrio.
    assert len(set_spy.calls) == 0
    assert len(click_spy.calls) == 0


def test_seguridad_open_first_false_label_no_coincide_aborta(monkeypatch):
    open_spy, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch,
        eval_fn=_make_eval(label="Escribir un mensaje para el grupo OTRO CHAT"))

    res = whatsapp_send_image("NOTAS WASAP", _IMG,
                              port=9222, target_url_substr="whatsapp",
                              open_first=False)

    assert res["sent"] is False
    assert "abortado por seguridad" in res["error"]
    # SEGURIDAD: no se adjunto ni se clicko nada.
    assert len(set_spy.calls) == 0
    assert len(click_spy.calls) == 0


def test_error_set_file_input_falla_no_envia(monkeypatch):
    state = {}
    open_spy, click_spy, set_spy, sendmsg_spy = _patch_common(
        monkeypatch, eval_fn=_make_eval(state=state),
        set_ret={"ok": False, "error": "no element matches selector"})

    res = whatsapp_send_image("NOTAS WASAP", _IMG,
                              port=9222, target_url_substr="whatsapp")

    assert res["sent"] is False
    assert "no se pudo adjuntar" in res["error"]
    # Se abrio Adjuntar (1 click) e intento adjuntar (1 set), pero NO se envio nada.
    assert len(set_spy.calls) == 1
    assert len(click_spy.calls) == 1
    assert len(sendmsg_spy.calls) == 0
