#!/bin/bash

# Modular system config generator for LibrePortal
# Production version - no sourcing, let production handle loading

# Main system config generator - single unified JSON file
webuiGenerateSystemConfigs() {
    isNotice "Generating unified configuration file..."

    # JSON string escape: backslash, double-quote, and control chars.
    jsonEscape() {
        local s="$1"
        s="${s//\\/\\\\}"
        s="${s//\"/\\\"}"
        s="${s//$'\t'/\\t}"
        s="${s//$'\r'/\\r}"
        s="${s//$'\n'/\\n}"
        printf '%s' "$s"
    }

    # Split a "# Title - Description [opt1|opt2|opt3]" comment on the FIRST ' - '.
    # Sets globals splitTitle / splitDesc / splitOptions. Falls back to whole-
    # string-as-desc. splitOptions is a JSON array string ready to drop into
    # the configs.json output; empty string when there's no [...] in the comment.
    #
    # Bracket syntax (both forms supported, in the same bracket):
    #   [value1|value2|value3]                   — value used as label
    #   [value1:Label 1|value2:Label 2]          — explicit labels
    #   [value1:Label 1|value2]                  — mix, fine
    splitTitleDesc() {
        local s="$1"
        local options_raw=""

        # Pull off the trailing [opt1|opt2|...] block if present (we want it
        # OUT of the description so the user-visible description stays clean).
        # bash ERE: [^]]+ matches "any char except ]". We don't also need to
        # forbid [ in the class because (.*) is greedy and will swallow
        # everything up to the LAST [ before the closing ].
        if [[ "$s" =~ ^(.*)\[([^]]+)\][[:space:]]*$ ]]; then
            s="${BASH_REMATCH[1]}"
            options_raw="${BASH_REMATCH[2]}"
            s="${s%"${s##*[![:space:]]}"}"
        fi

        if [[ "$s" == *" - "* ]]; then
            splitTitle="${s%% - *}"
            splitDesc="${s#* - }"
        else
            splitTitle=""
            splitDesc="$s"
        fi
        splitTitle="${splitTitle%"${splitTitle##*[![:space:]]}"}"
        splitDesc="${splitDesc%"${splitDesc##*[![:space:]]}"}"

        splitOptions=""
        if [[ -n "$options_raw" ]]; then
            local entry tok val lbl pairs=""
            IFS='|' read -ra _opts <<< "$options_raw"
            for entry in "${_opts[@]}"; do
                entry="${entry#"${entry%%[![:space:]]*}"}"
                entry="${entry%"${entry##*[![:space:]]}"}"
                [[ -z "$entry" ]] && continue
                if [[ "$entry" == *:* ]]; then
                    val="${entry%%:*}"
                    lbl="${entry#*:}"
                else
                    val="$entry"
                    lbl="$entry"
                fi
                val="${val#"${val%%[![:space:]]*}"}"; val="${val%"${val##*[![:space:]]}"}"
                lbl="${lbl#"${lbl%%[![:space:]]*}"}"; lbl="${lbl%"${lbl##*[![:space:]]}"}"
                val=$(jsonEscape "$val")
                lbl=$(jsonEscape "$lbl")
                [[ -n "$pairs" ]] && pairs+=","
                pairs+="{\"value\":\"$val\",\"label\":\"$lbl\"}"
            done
            [[ -n "$pairs" ]] && splitOptions="[$pairs]"
        fi
    }

    local output_file="${containers_dir}libreportal/frontend/data/config/generated/configs.json"
    local temp_file="$(mktemp)"

    runFileOp mkdir -p "$(dirname "$output_file")"

    # Cache category metadata in one read pass per .category file.
    # Previously each of TITLE/DESCRIPTION/ICON/SUBCATEGORY_ORDER/ORDER cost
    # a separate `grep | cut` fork — 5 forks × 8 categories was 40 forks
    # just to discover metadata.
    declare -A _cat_title _cat_desc _cat_icon _cat_suborder _cat_order
    local categories_in_order=()
    local category_dir category_name k v
    for category_dir in "$configs_dir"/*; do
        [[ -d "$category_dir" && -f "$category_dir/.category" ]] || continue
        category_name="${category_dir##*/}"
        while IFS='=' read -r k v || [[ -n "$k" ]]; do
            v="${v%$'\r'}"
            case "$k" in
                TITLE)             _cat_title[$category_name]="$v" ;;
                DESCRIPTION)       _cat_desc[$category_name]="$v" ;;
                ICON)              _cat_icon[$category_name]="$v" ;;
                SUBCATEGORY_ORDER) _cat_suborder[$category_name]="$v" ;;
                ORDER)             _cat_order[$category_name]="$v" ;;
            esac
        done < "$category_dir/.category"
        categories_in_order+=("${_cat_order[$category_name]}:$category_name")
    done

    # Sort categories by ORDER number
    IFS=$'\n' categories_in_order=($(sort -n <<<"${categories_in_order[*]}"))
    unset IFS

    # Start unified JSON structure in temp file
    cat > "$temp_file" << 'EOF'
{
  "configType": "unified",
  "name": "LibrePortal Configuration",
  "description": "Complete system configuration with categories",
  "categories": {
EOF

    # Generate categories section
    local total_categories=${#categories_in_order[@]}
    local i category_info title description icon subcategory_order
    for i in "${!categories_in_order[@]}"; do
        category_info="${categories_in_order[$i]}"
        category_name="${category_info#*:}"
        title="${_cat_title[$category_name]}"
        description="${_cat_desc[$category_name]}"
        icon="${_cat_icon[$category_name]}"
        subcategory_order="${_cat_suborder[$category_name]}"

        printf '    "%s": {\n' "$category_name" >> "$temp_file"
        printf '      "title": "%s",\n' "$title" >> "$temp_file"
        printf '      "description": "%s",\n' "$description" >> "$temp_file"
        printf '      "icon": "%s",\n' "$icon" >> "$temp_file"
        printf '      "subcategory_order": "%s"\n' "$subcategory_order" >> "$temp_file"
        if [[ $i -eq $((total_categories - 1)) ]]; then
            printf '    }\n' >> "$temp_file"
        else
            printf '    },\n' >> "$temp_file"
        fi
    done

    cat >> "$temp_file" << 'EOF'
  },
  "subcategories": {
EOF

    # Subcategories section
    local first_subcategory=true subcategories subcategory config_file
    local header_line hdr _l _read_count
    for category_info in "${categories_in_order[@]}"; do
        category_name="${category_info#*:}"
        category_dir="$configs_dir/$category_name"
        subcategory_order="${_cat_suborder[$category_name]}"

        IFS=',' read -ra subcategories <<< "$subcategory_order"
        for subcategory in "${subcategories[@]}"; do
            config_file="$category_dir/$subcategory"
            [[ -f "$config_file" ]] || continue

            # Find the first header comment ("# Title - Description") in the
            # first 5 lines of the file. Was `head -5 | grep | head -1` (3
            # forks); now pure bash.
            header_line=""
            _read_count=0
            while IFS= read -r _l && (( _read_count < 5 )); do
                ((_read_count++))
                if [[ "$_l" == \#*' - '* ]]; then
                    header_line="$_l"
                    break
                fi
            done < "$config_file"

            title=""
            description=""
            if [[ -n "$header_line" ]]; then
                hdr="${header_line#\#}"
                hdr="${hdr#"${hdr%%[![:space:]]*}"}"
                splitTitleDesc "$hdr"
                title="$splitTitle"
                description="$splitDesc"
            fi
            [[ -z "$title" ]] && title="${subcategory//_/ }"
            [[ -z "$description" ]] && description="Subcategory configuration"
            title="${title#"${title%%[![:space:]]*}"}"
            title="${title%"${title##*[![:space:]]}"}"
            description="${description#"${description%%[![:space:]]*}"}"
            description="${description%"${description##*[![:space:]]}"}"
            title=$(jsonEscape "$title")
            description=$(jsonEscape "$description")

            if [[ $first_subcategory == true ]]; then
                first_subcategory=false
                printf '    "%s": {\n' "$subcategory" >> "$temp_file"
            else
                printf '    ,"%s": {\n' "$subcategory" >> "$temp_file"
            fi
            printf '      "title": "%s",\n' "$title" >> "$temp_file"
            printf '      "description": "%s",\n' "$description" >> "$temp_file"
            printf '      "category": "%s"\n' "$category_name" >> "$temp_file"
            printf '    }\n' >> "$temp_file"
        done
    done

    cat >> "$temp_file" << 'EOF'
  },
  "config": {
EOF

    # Config section — main hot loop. Was 7 forks per CFG line via
    # `cut`/`sed`/`tr` pipes; now pure bash parameter expansion.
    local first_config=true line var_name rest var_value comment
    for category_info in "${categories_in_order[@]}"; do
        category_name="${category_info#*:}"
        category_dir="$configs_dir/$category_name"
        subcategory_order="${_cat_suborder[$category_name]}"

        IFS=',' read -ra subcategories <<< "$subcategory_order"
        for subcategory in "${subcategories[@]}"; do
            config_file="$category_dir/$subcategory"
            [[ -f "$config_file" ]] || continue

            while IFS= read -r line || [[ -n "$line" ]]; do
                [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
                [[ "$line" =~ ^CFG_[A-Z0-9_]+= ]] || continue

                var_name="${line%%=*}"
                rest="${line#*=}"

                # Value = everything before first '#' on the rest.
                if [[ "$rest" == *#* ]]; then
                    var_value="${rest%%#*}"
                    comment="${rest#*#}"
                else
                    var_value="$rest"
                    comment=""
                fi
                # Strip \r, trailing whitespace.
                var_value="${var_value//$'\r'/}"
                var_value="${var_value%"${var_value##*[![:space:]]}"}"

                title=""
                description=""
                if [[ -n "$comment" ]]; then
                    comment="${comment#"${comment%%[![:space:]]*}"}"
                    splitTitleDesc "$comment"
                    title="$splitTitle"
                    description="$splitDesc"
                fi

                # Remove outer quotes if present.
                if [[ "$var_value" =~ ^\"(.*)\"$ ]]; then
                    var_value="${BASH_REMATCH[1]}"
                fi

                var_value=$(jsonEscape "$var_value")
                title=$(jsonEscape "$title")
                description=$(jsonEscape "$description")

                if [[ $first_config == true ]]; then
                    first_config=false
                    printf '    "%s": {\n' "$var_name" >> "$temp_file"
                else
                    printf '    ,"%s": {\n' "$var_name" >> "$temp_file"
                fi
                printf '      "value": "%s",\n' "$var_value" >> "$temp_file"
                printf '      "category": "%s",\n' "$category_name" >> "$temp_file"
                printf '      "subcategory": "%s"\n' "$subcategory" >> "$temp_file"

                if [[ -n "$title" || -n "$description" || -n "$splitOptions" ]]; then
                    printf ',\n' >> "$temp_file"
                fi
                [[ -n "$title" ]]        && printf '      "title": "%s",\n' "$title" >> "$temp_file"
                [[ -n "$description" ]]  && printf '      "description": "%s"' "$description" >> "$temp_file"
                if [[ -n "$splitOptions" ]]; then
                    [[ -n "$description" ]] && printf ',\n' >> "$temp_file"
                    printf '      "options": %s\n' "$splitOptions" >> "$temp_file"
                elif [[ -n "$description" ]]; then
                    printf '\n' >> "$temp_file"
                fi
                printf '    }\n' >> "$temp_file"
            done < "$config_file"
        done
    done

    # Per-location keys live in configs/backup/locations/<n>/location.config,
    # which the flat-file loop above never descends into. Emit them here so the
    # Locations editor renders from config metadata like every other page. A
    # "**ADVANCED**" token anywhere in a field's comment marks it for the
    # editor's "Advanced" reveal (stripped from the user-facing description).
    local loc_cfg loc_advanced
    for loc_cfg in "$configs_dir"/backup/locations/*/location.config; do
        [[ -f "$loc_cfg" ]] || continue
        while IFS= read -r line || [[ -n "$line" ]]; do
            [[ -z "$line" || "$line" =~ ^[[:space:]]*# ]] && continue
            [[ "$line" =~ ^CFG_BACKUP_LOC_[0-9]+_[A-Z0-9_]+= ]] || continue

            var_name="${line%%=*}"
            rest="${line#*=}"
            if [[ "$rest" == *#* ]]; then
                var_value="${rest%%#*}"
                comment="${rest#*#}"
            else
                var_value="$rest"
                comment=""
            fi
            var_value="${var_value//$'\r'/}"
            var_value="${var_value%"${var_value##*[![:space:]]}"}"

            loc_advanced="false"
            title=""
            description=""
            splitOptions=""
            if [[ -n "$comment" ]]; then
                comment="${comment#"${comment%%[![:space:]]*}"}"
                if [[ "$comment" == *'**ADVANCED**'* ]]; then
                    loc_advanced="true"
                    comment="${comment//\*\*ADVANCED\*\*/}"
                    comment="${comment%"${comment##*[![:space:]]}"}"
                fi
                splitTitleDesc "$comment"
                title="$splitTitle"
                description="$splitDesc"
            fi

            if [[ "$var_value" =~ ^\"(.*)\"$ ]]; then
                var_value="${BASH_REMATCH[1]}"
            fi
            var_value=$(jsonEscape "$var_value")
            title=$(jsonEscape "$title")
            description=$(jsonEscape "$description")

            if [[ $first_config == true ]]; then
                first_config=false
                printf '    "%s": {\n' "$var_name" >> "$temp_file"
            else
                printf '    ,"%s": {\n' "$var_name" >> "$temp_file"
            fi
            printf '      "value": "%s",\n' "$var_value" >> "$temp_file"
            printf '      "category": "backup",\n' >> "$temp_file"
            printf '      "subcategory": "backup_locations",\n' >> "$temp_file"
            printf '      "advanced": %s' "$loc_advanced" >> "$temp_file"
            if [[ -n "$title" || -n "$description" || -n "$splitOptions" ]]; then
                printf ',\n' >> "$temp_file"
            else
                printf '\n' >> "$temp_file"
            fi
            [[ -n "$title" ]]       && printf '      "title": "%s",\n' "$title" >> "$temp_file"
            [[ -n "$description" ]] && printf '      "description": "%s"' "$description" >> "$temp_file"
            if [[ -n "$splitOptions" ]]; then
                [[ -n "$description" ]] && printf ',\n' >> "$temp_file"
                printf '      "options": %s\n' "$splitOptions" >> "$temp_file"
            elif [[ -n "$description" ]]; then
                printf '\n' >> "$temp_file"
            fi
            printf '    }\n' >> "$temp_file"
        done < "$loc_cfg"
    done

    cat >> "$temp_file" << 'EOF'

  }
}
EOF

    # Already running as root via start.sh — sudo was redundant overhead.
    if [ $? -eq 0 ]; then
        runFileWrite "$output_file" < "$temp_file"; rm -f "$temp_file"
    else
        rm -f "$temp_file" 2>/dev/null
    fi
}
