#!/usr/bin/env bash
# save_onlyoffice_file — fuerza el guardado (Ctrl+S) de un documento abierto en una
# instancia de ONLYOFFICE Desktop Editors en Linux/X11 y confirma que el archivo se
# escribio a disco observando el cambio de mtime.
#
# Para que existe: OnlyOffice mantiene los cambios en memoria hasta que el usuario
# guarda. Cualquier proceso que regenere el .xlsx leyendo del disco (por ejemplo un
# build que refresca hojas) perderia el trabajo manual no guardado. Esta funcion
# vuelca ese trabajo a disco ANTES de tocar el archivo, de modo que el paso de
# actualizacion pueda preservarlo. Es el primer paso del flujo seguro:
#   save_onlyoffice_file -> (actualizar el archivo) -> reload_onlyoffice_file
#
# La ventana se localiza por el basename del archivo (OnlyOffice titula la ventana
# "<basename> — ONLYOFFICE"), igual que open_onlyoffice_file. Si no hay ventana
# abierta para ese basename no hay nada que guardar: se devuelve status "no_window"
# con exit 0 (el disco ya es la unica fuente de verdad).
#
# Funcion impura: envia eventos de teclado a X11 (xdotool) y lee el estado del
# sistema de archivos. Imprime una linea JSON con el resultado a stdout.
#
# No usamos `set -e`: los pipelines de busqueda de ventanas (xdotool|head) pueden no
# matchear y no deben abortar el script. Mantenemos -u y pipefail con guardas.
set -uo pipefail

save_onlyoffice_file() {
    local file_path="${1:-}"
    local instance="${2:-demo}"

    # --- 1. Validacion de dependencias del sistema ---
    local dep
    for dep in xdotool stat; do
        if ! command -v "$dep" >/dev/null 2>&1; then
            echo "error: dependencia ausente: '$dep' (instala xdotool, coreutils)" >&2
            return 1
        fi
    done

    # --- 2. Validacion de argumentos ---
    if [ -z "$file_path" ]; then
        echo "error: uso: save_onlyoffice_file <file_path> [instance]" >&2
        return 1
    fi
    if [ ! -f "$file_path" ]; then
        echo "error: el archivo no existe: '$file_path'" >&2
        return 1
    fi
    local abs_path
    abs_path="$(cd "$(dirname "$file_path")" && pwd)/$(basename "$file_path")"
    local base
    base="$(basename "$abs_path")"

    # --- 3. Localizar la ventana de OnlyOffice por basename ---
    local wid=""
    wid="$(xdotool search --name "$base" 2>/dev/null | head -1 || true)"
    if [ -z "$wid" ]; then
        printf '{"instance":"%s","file":"%s","wid":null,"status":"no_window"}\n' \
            "$instance" "$abs_path"
        return 0
    fi
    local hex
    hex="$(printf '0x%08x' "$wid" 2>/dev/null || echo "$wid")"

    # --- 4. mtime antes de guardar ---
    local mtime_before
    mtime_before="$(stat -c %Y "$abs_path" 2>/dev/null || echo 0)"

    # --- 5. Enfocar la ventana y enviar Ctrl+S ---
    xdotool windowactivate --sync "$wid" >/dev/null 2>&1 || true
    xdotool key --clearmodifiers --window "$wid" ctrl+s >/dev/null 2>&1 || true

    # --- 6. Esperar el guardado; auto-confirmar el dialogo de formato si aparece ---
    # OnlyOffice puede mostrar un dialogo modal ("mantener formato") al guardar. Si el
    # mtime no cambia en ~1.2s asumimos que hay un modal esperando y le enviamos Return:
    # acepta la opcion por defecto, que es mantener el formato actual del archivo. Si no
    # habia dialogo, el Return va al editor y solo mueve de celda (inofensivo: no altera
    # datos). El intento se repite mientras el guardado no se confirme.
    local mtime_after="$mtime_before" i=0 confirmed=0
    local max=27   # ~8s a 0.3s por iteracion
    until [ "$mtime_after" -gt "$mtime_before" ] || [ "$i" -ge "$max" ]; do
        read -r -t 0.3 _ </dev/null 2>/dev/null || true
        mtime_after="$(stat -c %Y "$abs_path" 2>/dev/null || echo "$mtime_before")"
        i=$((i + 1))
        # A partir de ~1.2s sin guardar, confirmar el dialogo modal con Return.
        if [ "$i" -ge 4 ] && [ "$mtime_after" -le "$mtime_before" ]; then
            local dlg
            dlg="$(xdotool getactivewindow 2>/dev/null || true)"
            if [ -n "$dlg" ]; then
                xdotool key --clearmodifiers --window "$dlg" Return >/dev/null 2>&1 || true
                confirmed=1
            fi
        fi
    done

    local status="saved"
    if [ "$mtime_after" -le "$mtime_before" ]; then
        # Sin cambio de mtime: no habia nada pendiente que guardar.
        status="no_change"
    fi
    printf '{"instance":"%s","file":"%s","wid":"%s","status":"%s","dialog_confirmed":%s,"mtime_before":%s,"mtime_after":%s}\n' \
        "$instance" "$abs_path" "$hex" "$status" "$confirmed" "$mtime_before" "$mtime_after"
    return 0
}

# Ejecutable directo: `bash save_onlyoffice_file.sh <file> [instance]`.
if [ "${BASH_SOURCE[0]}" = "${0}" ]; then
    save_onlyoffice_file "$@"
fi
