#!/bin/bash

# Reconcile a live config file against its template (the freshly-cloned repo):
#   - keep the user's existing value for any key the template still defines
#   - add new template keys                     (CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE)
#   - drop keys the template no longer defines  (CFG_REQUIREMENT_CONFIGS_AUTO_DELETE)
#   - take the COMMENT (title, description, [options], **DEV** / **ADVANCED**
#     markers) from the template, so label / metadata / marker changes shipped
#     in a release reach existing installs without nuking user values.
# Structure, ordering and comments follow the template. Non-interactive, atomic,
# and keeps a hidden .<file>.bak sibling (dot-named so backups don't clutter the
# configs folder and can never be picked up by the config walkers/sourcing).
# Refuses to act on a missing/empty template so a broken clone can never wipe a
# live config.

# Split `CFG_KEY=value...#comment` into its value-part and comment-part.
# Used by reconcileConfigFile to swap the template's comment onto the user's
# value. Sets _reconcile_value and _reconcile_comment as side outputs.
_reconcileSplitValueComment()
{
    local line="$1"
    # Drop the "CFG_KEY=" prefix; remainder is value [whitespace #comment].
    local rest="${line#*=}"
    if [[ "$rest" == *"#"* ]]; then
        _reconcile_value="${rest%%#*}"
        # Strip trailing whitespace from the value half.
        _reconcile_value="${_reconcile_value%"${_reconcile_value##*[![:space:]]}"}"
        _reconcile_comment="#${rest#*#}"
    else
        _reconcile_value="$rest"
        # Strip trailing whitespace from the value half.
        _reconcile_value="${_reconcile_value%"${_reconcile_value##*[![:space:]]}"}"
        _reconcile_comment=""
    fi
}

reconcileConfigFile()
{
    local live="$1" template="$2"
    local do_add="${CFG_REQUIREMENT_CONFIGS_AUTO_UPDATE:-true}"
    local do_delete="${CFG_REQUIREMENT_CONFIGS_AUTO_DELETE:-true}"

    [[ -f "$live" ]] || return 0
    runInstallOp test -s "$template" 2>/dev/null || return 0

    declare -A live_value live_line emitted
    local line key
    while IFS= read -r line; do
        if [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]]; then
            key="${BASH_REMATCH[1]}"
            _reconcileSplitValueComment "$line"
            live_value["$key"]="$_reconcile_value"
            live_line["$key"]="$line"
        fi
    done < <(runInstallOp cat "$live")

    local tmp; tmp=$(mktemp)
    local tmpl_value tmpl_comment merged
    while IFS= read -r line; do
        if [[ "$line" =~ ^(CFG_[A-Za-z0-9_]+)= ]]; then
            key="${BASH_REMATCH[1]}"
            _reconcileSplitValueComment "$line"
            tmpl_value="$_reconcile_value"
            tmpl_comment="$_reconcile_comment"

            if [[ -n "${live_value[$key]+x}" ]]; then
                # Keep the user's value, take the template's comment (so
                # title/description/options/markers stay in sync with the repo).
                if [[ -n "$tmpl_comment" ]]; then
                    merged="${key}=${live_value[$key]}     ${tmpl_comment}"
                else
                    merged="${key}=${live_value[$key]}"
                fi
                printf '%s\n' "$merged" >> "$tmp"
                emitted["$key"]=1
            elif [[ "$do_add" == "true" ]]; then
                printf '%s\n' "$line" >> "$tmp"                  # new key, template default
            fi
        else
            printf '%s\n' "$line" >> "$tmp"                      # comments / blanks / ordering
        fi
    done < <(runInstallOp cat "$template")

    if [[ "$do_delete" != "true" ]]; then                       # keep keys the template dropped
        for key in "${!live_line[@]}"; do
            [[ -n "${emitted[$key]+x}" ]] || printf '%s\n' "${live_line[$key]}" >> "$tmp"
        done
    fi

    # Replace only when the result is sane (non-empty, has keys) and differs.
    if [[ -s "$tmp" ]] && grep -q '^CFG_' "$tmp" && ! runInstallOp cmp -s "$tmp" "$live"; then
        local bak_file="${live%/*}/.${live##*/}.bak"
        runCfgOp cp -a "$live" "$bak_file"
        { [[ -n "$containers_dir" && "$live" == "$containers_dir"* ]] && runFileWrite "$live" < "$tmp" || runInstallOp cp "$tmp" "$live"; }
        # A hidden .<file>.bak sibling is still written above for safety; the
        # per-file result is intentionally silent — the intro notice and the
        # per-section "...completed." lines are the only reconcile output.
    fi
    rm -f "$tmp"
}

checkConfigFilesMissingVariables()
{
    local showheader="$1"

    [[ "$CFG_REQUIREMENT_CONFIGS_CHECK" == "true" ]] || return 0
    [[ "$showheader" == "true" ]] && isHeader "Scanning Config Files"
    isNotice "Reconciling config files against templates...please wait"

    checkLibrePortalConfigFilesMissingVariables;
    checkApplicationsConfigFilesMissingVariables;
}
