#!/bin/bash

# LibrePortal Tag Update Manager
# Handles tag content replacement

# Update any tag (universal for both states)
tagsManagerUpdateUniversalTag()
{
    local file_path="$1"
    local tag_name="$2"
    local new_content="$3"

    # Capture this tag's current value from the first matching annotation.
    # The form is `#LIBREPORTAL|<TAG>|<VALUE>` and <VALUE> terminates at the
    # next pipe, whitespace, or EOL — it never contains another #LIBREPORTAL
    # marker. The previous `awk -F'|' '{print $3}' | head -1` was greedy:
    # when a line carried two annotations (e.g. nextcloud's trusted-domains
    # row) $3 captured "VALUE #LIBREPORTAL", which then propagated into both
    # sed steps and corrupted unrelated lines on subsequent calls.
    local current_placeholder
    current_placeholder=$(awk -v t="$tag_name" '
        {
            marker = "#LIBREPORTAL|" t "|"
            p = index($0, marker)
            if (p == 0) next
            rest = substr($0, p + length(marker))
            n = match(rest, /[| \t\r]/)
            if (n > 0) rest = substr(rest, 1, n - 1)
            print rest
            exit
        }
    ' "$file_path")

    # Tag not present (or already empty) — nothing to do.
    [[ -z "$current_placeholder" ]] && return 0
    # Already at target — skip (idempotent, also avoids self-heal churn).
    [[ "$current_placeholder" == "$new_content" ]] && return 0

    # Escape regex metachars in the search pattern and replacement chars
    # in the replacement. We use | as the sed delimiter, so | needs
    # escaping in both halves. Without this, a previously-set value like
    # `nextcloud.` would have its `.` interpreted as any-char, matching
    # `nextcloud-` elsewhere on the same line.
    local esc_placeholder esc_new
    esc_placeholder=$(printf '%s' "$current_placeholder" | sed 's/[][\\.*^$/|]/\\&/g')
    esc_new=$(printf '%s' "$new_content" | sed 's/[\\&|]/\\&/g')

    # Single-pass substitution, scoped to lines carrying this tag's annotation.
    # The in-place edit runs AS the file's owner (no root): under
    # /docker/containers/<app> that's the docker install user (runFileOp); the
    # manager-owned configs/ + install templates use runInstallOp. The read
    # (awk above) needs no escalation — config/compose files are world-readable.
    local op="runInstallOp"
    [[ "$file_path" == "$containers_dir"* || "$file_path" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp"
    $op sed -i "/#LIBREPORTAL|${tag_name}|/s|${esc_placeholder}|${esc_new}|g" "$file_path"
}
