"""Mueve un mensaje IMAP a otro mailbox por UID, con fallback COPY+EXPUNGE.

Funcion IMPURA: traslada un mensaje (identificado por su UID) del mailbox
seleccionado a `dest_mailbox` sobre una conexion `imaplib.IMAP4_SSL` ya
autenticada. Intenta primero el comando UID MOVE (RFC 6851, soportado por Gmail
y la mayoria de servidores modernos): es atomico y eficiente. Si el servidor NO
anuncia la capacidad MOVE, cae a la secuencia clasica equivalente: UID COPY al
destino, STORE +FLAGS (\\Deleted) en el origen y EXPUNGE para materializar el
borrado del origen.

Nunca lanza: devuelve un dict con `status` ("ok"/"error") y `method` para indicar
que camino se uso. No abre la conexion ni resuelve credenciales: el caller pasa
`conn` ya conectado, autenticado y con `conn.select("<mailbox origen>")` hecho.
"""


def _server_supports_move(conn) -> bool:
    """Devuelve True si la conexion anuncia la capability MOVE (RFC 6851).

    Inspecciona ``conn.capabilities`` (tupla de capacidades que imaplib cachea
    tras el login). La comparacion es case-insensitive porque distintos servidores
    devuelven "MOVE" en mayusculas/minusculas. Cualquier problema accediendo a las
    capacidades se trata como "no soportado" para forzar el fallback seguro.
    """
    try:
        caps = getattr(conn, "capabilities", ()) or ()
        return any(str(c).upper() == "MOVE" for c in caps)
    except Exception:  # noqa: BLE001
        return False


def imap_move_message(conn, uid: int, dest_mailbox: str) -> dict:
    """Mueve el mensaje `uid` del mailbox seleccionado a `dest_mailbox`.

    Camino preferido (``method="move"``): ``conn.uid("MOVE", str(uid),
    dest_mailbox)``, atomico. Si el servidor no soporta MOVE (no esta en
    ``conn.capabilities``) o el comando MOVE falla, se usa el fallback
    (``method="copy_delete"``): ``UID COPY`` al destino, ``UID STORE +FLAGS
    (\\Deleted)`` en el origen y ``EXPUNGE``.

    Args:
        conn: objeto ``imaplib.IMAP4_SSL`` (o ``IMAP4``) YA conectado,
            autenticado y con el mailbox ORIGEN seleccionado (``conn.select(...)``).
        uid: UID del mensaje en el mailbox origen. Operacion siempre por UID, no
            por numero de secuencia.
        dest_mailbox: nombre del mailbox destino. En Gmail los nombres llevan el
            prefijo ``[Gmail]/`` (ej. ``"[Gmail]/Trash"`` para la papelera,
            ``"[Gmail]/Spam"``). Una carpeta de usuario es simplemente su nombre.

    Returns:
        dict. En exito: ``{"status": "ok", "uid": uid, "dest": dest_mailbox,
        "method": "move" | "copy_delete"}``. En fallo (sin lanzar):
        ``{"status": "error", "error": str}``.
    """
    try:
        # Camino 1: UID MOVE (atomico) si el servidor lo anuncia.
        if _server_supports_move(conn):
            try:
                typ, data = conn.uid("MOVE", str(uid), dest_mailbox)
                if typ == "OK":
                    return {
                        "status": "ok",
                        "uid": uid,
                        "dest": dest_mailbox,
                        "method": "move",
                    }
                # MOVE anunciado pero rechazado: caemos al fallback.
            except Exception:  # noqa: BLE001
                # MOVE no soportado en la practica pese a la capability: fallback.
                pass

        # Camino 2 (fallback): COPY al destino + marcar \\Deleted en origen + EXPUNGE.
        typ, data = conn.uid("COPY", str(uid), dest_mailbox)
        if typ != "OK":
            return {
                "status": "error",
                "error": f"imap_move_message: COPY a {dest_mailbox!r} devolvio {typ!r}: {data!r}",
            }

        typ, data = conn.uid("STORE", str(uid), "+FLAGS", "(\\Deleted)")
        if typ != "OK":
            return {
                "status": "error",
                "error": f"imap_move_message: STORE \\Deleted devolvio {typ!r}: {data!r}",
            }

        conn.expunge()
        return {
            "status": "ok",
            "uid": uid,
            "dest": dest_mailbox,
            "method": "copy_delete",
        }
    except Exception as e:  # noqa: BLE001
        return {"status": "error", "error": str(e)}


if __name__ == "__main__":
    print("imap_move_message: importable. Uso real requiere un conn IMAP autenticado.")
