#!/usr/bin/env bash
set -e

# --- Parámetros ---
APPEND_ARRAY=0
DELETE_MODE=0

while [[ $# -gt 0 ]]; do
    case $1 in
        -f|--file)
        FICH="$2"; shift 2;;
        -c|--channel)
        CANAL="$2"; shift 2;;
        -p|--path)
        DIRECTIVA="$2"; shift 2;;
        -s|--set)
        VALOR="$2"; shift 2;;
        --type)
            TIPO="$2"
            [[ "${TIPO}" == "null" ]] && \
            echo "#> TIPO: ${TIPO}. El valor de \"type\" no puede ser un \"null\", lo dejamos en blanco" && \
            TIPO=""
        shift 2;;
        --append-array)
        APPEND_ARRAY=1; shift;;
        --delete)
        DELETE_MODE=1; shift;;
        *)
        echo "Error: parámetro desconocido '$1'"; exit 1;;
    esac
done

# Si no indicamos CANAL es porque se omite que el nombre del canal es el nombre del archivo sin la extensión xml:
[[ "$FICH" && ! "$CANAL" ]] && CANAL="${FICH/.*}"

if [[ -z "$FICH" || -z "$CANAL" || -z "$DIRECTIVA" ]]; then
    echo "Uso: Si no indicamos CANAL e omite que el nombre del canal es el nombre del archivo sin la extensión xml"
    echo "$0 -f fichero.xml -c canal -p propA/propB -s valor [--type tipo] [--append-array] [--delete]"
    exit 1
fi

# Eliminar barra inicial si existe
DIRECTIVA="${DIRECTIVA#/}"
IFS='/' read -ra PARTES <<< "$DIRECTIVA"

# --- Construcción del XPATH ---
XPATH="/channel[@name='${CANAL}']"
for P in "${PARTES[@]}"; do
    XPATH="${XPATH}/property[@name='${P}']"
done

echo "#> XPATH: $DIRECTIVA => $XPATH"

XPATH_VAL="${XPATH}/@value"
XPATH_TYPE="${XPATH}/@type"

# Función que permite obtener el valor actual:
get_valor_actual() {
    local VAL
    VAL=$(xmlstarlet sel -t -v "${XPATH_VAL}" "$FICH" 2>/dev/null || true)
    echo "$VAL"
}

# Comprobamos si el campo value existe en un nodo existente, ya que puede existir y no tener definido un valor:
# Ej. xfwm4.xml: <property name="activate_action" type="empty"/>
value_existe() {
    xmlstarlet sel -t -v "${XPATH_VAL}" "$FICH" 2>/dev/null | grep -q .
}

# --- Función auxiliar: comprobar existencia ---
existe_nodo() {
    xmlstarlet sel -t -c "$XPATH" "$FICH" 2>/dev/null | grep -q "<property"
}

existe_array_value() {
    xmlstarlet sel -t -c "${XPATH}/value[@value='${VALOR}']" "$FICH" 2>/dev/null | grep -q "<value"
}

# --- Modo DELETE ---
if (( DELETE_MODE == 1 )); then
    echo "Eliminando propiedad ${DIRECTIVA}…"
    xmlstarlet ed --delete "$XPATH" "$FICH" | sponge "$FICH"
    exit 0
fi

# --- Modo actualización si existe ---
if existe_nodo; then
    VALOR_ACTUAL=$(get_valor_actual)
    # --- Caso ARRAY ---
    TYPE_ACTUAL=$(xmlstarlet sel -t -v "$XPATH_TYPE" "$FICH" 2>/dev/null || true)
    # Si type es empty es porque la directiva esta sin definir tipo y valor
    if [[ "$TYPE_ACTUAL" == "empty" ]]; then
        TYPE_ACTUAL=""
    fi

    if [[ "$TYPE_ACTUAL" == "array" ]]; then
        if (( APPEND_ARRAY == 1 )); then
            if existe_array_value; then
                echo "Valor ya está en el array, nada que hacer."
            else
                echo "Añadiendo valor al array…"
                xmlstarlet ed \
                    --subnode "$XPATH" -t elem -n "value" -v "" \
                    --insert "${XPATH}/value[not(@type)][last()]" -t attr -n "type" -v "int" \
                    --insert "${XPATH}/value[@type='int'][last()]" -t attr -n "value" -v "$VALOR" \
                    "$FICH" | sponge "$FICH"
            fi
            exit 0
        else
            echo "Sobrescribiendo array completo…"
            # Borrar array y crear nuevo
            xmlstarlet ed \
                --delete "${XPATH}/value" \
                "$FICH" | sponge "$FICH"
            # Crear nuevo array con valores separados por comas
            for i in $(echo "$VALOR" | tr ',' '\n'); do
                xmlstarlet ed \
                    --subnode "$XPATH" -t elem -n "value" -v "" \
                    --insert "${XPATH}/value[not(@type)][last()]" -t attr -n "type" -v "int" \
                    --insert "${XPATH}/value[@type='int'][last()]" -t attr -n "value" -v "$i" \
                    "$FICH" | sponge "$FICH"
            done
            exit 0
        fi
    fi

    # Comprobamos si hay que especificar el tipo en la edición del XML
    if [[ -n "$TIPO" ]]; then
        if [[ -z "$TYPE_ACTUAL" ]]; then
            # type era vacío o empty → se puede añadir/actualizar
            echo "#> Actualizando tipo (era empty o no definido): $TIPO"
            UPDATE_TYPE=(--update "$XPATH_TYPE" --value "$TIPO")
        else
            # type existente y real → NO se modifica
            UPDATE_TYPE=()
        fi
    else
        UPDATE_TYPE=()
    fi

    # --- Caso valor simple ---
    echo "#> Actualizando valor existente:"
    echo "#> Valor actual: \"${VALOR_ACTUAL}\" => Nuevo valor: \"${VALOR}\""
    # Si el value no existe, hay que crearlo
    if ! value_existe; then
        echo "#> El atributo 'value' no existe, se creará: $VALOR"
        xmlstarlet ed \
            --insert "$XPATH" --type attr --name value --value "$VALOR" \
            --update "$XPATH_VAL" \
            --value "$VALOR" \
            ${UPDATE_TYPE[@]} \
            "$FICH" | sponge "$FICH"
    else
        xmlstarlet ed \
            --update "$XPATH_VAL" \
            --value "$VALOR" \
            ${UPDATE_TYPE[@]} \
            "$FICH" | sponge "$FICH"
    fi
    exit 0
fi

# --- Modo CREACIÓN: el nodo NO EXISTE ---
echo "Creando nueva propiedad ${DIRECTIVA}…"

CMD=(xmlstarlet ed)

CURRENT="/channel[@name='${CANAL}']"

for P in "${PARTES[@]}"; do
    CURRENT_NEXT="${CURRENT}/property[@name='${P}']"
    CMD+=(--subnode "$CURRENT" -t elem -n "property")
    CMD+=(--insert "$CURRENT/property[not(@name)][last()]" -t attr -n "name" -v "$P")
    CURRENT="$CURRENT_NEXT"
done

# Crear valor
CMD+=(--insert "$CURRENT" -t attr -n "value" -v "$VALOR")

# Crear tipo si se especifica
if [[ -n "$TIPO" ]]; then
    CMD+=(--insert "$CURRENT" -t attr -n "type" -v "$TIPO")
fi

"${CMD[@]}" "$FICH" | sponge "$FICH"
