#!/bin/sh
# SecuBox Configuration Vault - Versioned config backup with Gitea sync
# Supports cloning, deployment templates, and audit trail for certifications

. /lib/functions.sh

VAULT_PATH=""
GITEA_URL=""
GITEA_REPO=""
GITEA_BRANCH=""
GITEA_TOKEN=""
AUTO_COMMIT=""
AUTO_PUSH=""

# Module tracking
MODULES=""

# Load configuration
load_config() {
    config_load config-vault

    config_get VAULT_PATH global vault_path "/srv/config-vault"
    config_get AUTO_COMMIT global auto_commit "1"
    config_get AUTO_PUSH global auto_push "1"

    config_get GITEA_URL gitea url ""
    config_get GITEA_REPO gitea repo ""
    config_get GITEA_BRANCH gitea branch "main"

    # Get token from gitea config (shared)
    GITEA_TOKEN=$(uci -q get gitea.main.api_token)
}

# Initialize vault repository
cmd_init() {
    load_config

    echo "Initializing Configuration Vault..."

    # Create vault directory
    mkdir -p "$VAULT_PATH"
    cd "$VAULT_PATH" || exit 1

    # Check if already initialized
    if [ -d ".git" ]; then
        echo "Vault already initialized at $VAULT_PATH"
        return 0
    fi

    # Initialize git repo
    git init
    git config user.name "SecuBox Vault"
    git config user.email "vault@secubox.local"

    # Create directory structure for modules
    config_load config-vault
    config_foreach create_module_dir module

    # Create README
    cat > README.md << 'EOF'
# SecuBox Configuration Vault

Versioned configuration backups for SecuBox appliance.

## Structure

Each module has its own directory containing:
- `uci/` - UCI configuration exports (key=value format)
- `json/` - JSON exports for portability
- `flat/` - Flat file backups (certificates, keys, etc.)

## Modules

| Module | Description |
|--------|-------------|
| users | User Management & SSO |
| network | Network Configuration |
| services | Service Exposure & Distribution |
| security | Security & WAF |
| system | System Settings |
| containers | LXC Containers |
| reporter | Report Generator |
| dns | DNS & Domains |
| mesh | P2P Mesh Network |

## Usage

```bash
# Backup all modules
configvaultctl backup

# Backup specific module
configvaultctl backup users

# Restore from backup
configvaultctl restore users

# Clone to new device
configvaultctl export-clone > secubox-clone.tar.gz

# Push to Gitea
configvaultctl push
```

## Certification Compliance

All changes are versioned with timestamps and commit messages for audit trail.
EOF

    # Create .gitignore
    cat > .gitignore << 'EOF'
*.tmp
*.log
.DS_Store
EOF

    # Initial commit
    git add -A
    git commit -m "Initialize SecuBox Configuration Vault

System: $(cat /etc/openwrt_release | grep DISTRIB_ID | cut -d= -f2 | tr -d "'")
Version: $(cat /etc/openwrt_release | grep DISTRIB_RELEASE | cut -d= -f2 | tr -d "'")
Hostname: $(uci -q get system.@system[0].hostname)
Date: $(date -Iseconds)"

    # Setup remote if configured
    if [ -n "$GITEA_URL" ] && [ -n "$GITEA_REPO" ]; then
        local clone_url="${GITEA_URL}/${GITEA_REPO}.git"
        git remote add origin "$clone_url" 2>/dev/null || git remote set-url origin "$clone_url"
        echo "Remote configured: $clone_url"
    fi

    echo "Vault initialized at $VAULT_PATH"
}

# Create module directory structure
create_module_dir() {
    local section="$1"
    local enabled description

    config_get enabled "$section" enabled "1"
    [ "$enabled" = "1" ] || return

    config_get description "$section" description "$section"

    mkdir -p "$VAULT_PATH/$section/uci"
    mkdir -p "$VAULT_PATH/$section/json"
    mkdir -p "$VAULT_PATH/$section/flat"

    # Create module manifest
    cat > "$VAULT_PATH/$section/manifest.json" << EOF
{
    "module": "$section",
    "description": "$description",
    "created": "$(date -Iseconds)",
    "configs": []
}
EOF
}

# Backup a single UCI config
backup_uci_config() {
    local config="$1"
    local module="$2"
    local uci_file="/etc/config/$config"

    [ -f "$uci_file" ] || return 0

    # UCI format backup
    cp "$uci_file" "$VAULT_PATH/$module/uci/$config"

    # JSON format backup
    local json_out="$VAULT_PATH/$module/json/${config}.json"
    uci export "$config" 2>/dev/null | uci_to_json > "$json_out"
}

# Convert UCI output to JSON (simplified)
uci_to_json() {
    awk '
    BEGIN {
        print "{"
        first_section = 1
    }
    /^package/ {
        gsub(/'\''/, "", $2)
        printf "  \"package\": \"%s\",\n", $2
        printf "  \"sections\": [\n"
    }
    /^config/ {
        if (!first_section) print "    },"
        first_section = 0
        gsub(/'\''/, "", $2)
        gsub(/'\''/, "", $3)
        printf "    {\n      \"type\": \"%s\",\n      \"name\": \"%s\",\n      \"options\": {\n", $2, $3
        first_opt = 1
    }
    /option|list/ {
        if (!first_opt) print ","
        first_opt = 0
        gsub(/'\''/, "", $2)
        gsub(/'\''/, "\"", $3)
        # Handle multi-word values
        $1 = ""; $2 = ""
        gsub(/^ +/, "")
        gsub(/'\''/, "")
        printf "        \"%s\": \"%s\"", $2, $0
    }
    END {
        if (!first_section) {
            print "\n      }\n    }"
        }
        print "\n  ]\n}"
    }
    ' 2>/dev/null || echo '{"error": "parse_failed"}'
}

# Backup module
backup_module() {
    local module="$1"
    local configs description

    config_load config-vault

    local enabled
    config_get enabled "$module" enabled "1"
    [ "$enabled" = "1" ] || return

    config_get description "$module" description "$module"

    echo "Backing up module: $module ($description)"

    # Create directories
    mkdir -p "$VAULT_PATH/$module/uci"
    mkdir -p "$VAULT_PATH/$module/json"
    mkdir -p "$VAULT_PATH/$module/flat"

    # Get list of configs for this module
    config_list_foreach "$module" config backup_config_item "$module"

    # Update manifest
    cat > "$VAULT_PATH/$module/manifest.json" << EOF
{
    "module": "$module",
    "description": "$description",
    "backed_up": "$(date -Iseconds)",
    "hostname": "$(uci -q get system.@system[0].hostname)"
}
EOF
}

backup_config_item() {
    local config="$1"
    local module="$2"
    backup_uci_config "$config" "$module"
}

# Main backup command
cmd_backup() {
    local target="$1"

    load_config
    cd "$VAULT_PATH" || { echo "Vault not initialized. Run: configvaultctl init"; exit 1; }

    echo "Starting configuration backup..."
    echo "Timestamp: $(date -Iseconds)"
    echo ""

    config_load config-vault

    if [ -n "$target" ]; then
        # Backup specific module
        backup_module "$target"
    else
        # Backup all modules
        config_foreach backup_module module
    fi

    # Backup additional flat files
    backup_flat_files

    # Auto-commit if enabled
    if [ "$AUTO_COMMIT" = "1" ]; then
        local changes=$(git status --porcelain | wc -l)
        if [ "$changes" -gt 0 ]; then
            git add -A
            git commit -m "Config backup: $(date '+%Y-%m-%d %H:%M')

Modules: $(ls -d */ 2>/dev/null | tr -d '/' | tr '\n' ' ')
Changes: $changes files
Source: $(uci -q get system.@system[0].hostname)"

            echo ""
            echo "Changes committed: $changes files"

            # Auto-push if enabled
            if [ "$AUTO_PUSH" = "1" ] && [ -n "$GITEA_URL" ]; then
                cmd_push
            fi
        else
            echo "No changes detected."
        fi
    fi
}

# Backup important flat files
backup_flat_files() {
    echo "Backing up flat files..."

    # Users - export to JSON
    if [ -x /usr/sbin/secubox-users ]; then
        mkdir -p "$VAULT_PATH/users/flat"
        /usr/sbin/secubox-users list --json > "$VAULT_PATH/users/flat/users.json" 2>/dev/null || true
    fi

    # SSH keys
    mkdir -p "$VAULT_PATH/system/flat/ssh"
    [ -f /etc/dropbear/authorized_keys ] && cp /etc/dropbear/authorized_keys "$VAULT_PATH/system/flat/ssh/" 2>/dev/null

    # SSL certificates (public only)
    mkdir -p "$VAULT_PATH/security/flat/certs"
    for cert in /etc/ssl/certs/*.crt /etc/acme/*.cer; do
        [ -f "$cert" ] && cp "$cert" "$VAULT_PATH/security/flat/certs/" 2>/dev/null
    done

    # HAProxy configs
    mkdir -p "$VAULT_PATH/services/flat"
    [ -f /etc/haproxy.cfg ] && cp /etc/haproxy.cfg "$VAULT_PATH/services/flat/" 2>/dev/null

    # Container definitions
    mkdir -p "$VAULT_PATH/containers/flat"
    for cfg in /srv/lxc/*/config; do
        [ -f "$cfg" ] && {
            local name=$(dirname "$cfg" | xargs basename)
            cp "$cfg" "$VAULT_PATH/containers/flat/${name}.config" 2>/dev/null
        }
    done
}

# Push to Gitea
cmd_push() {
    load_config
    cd "$VAULT_PATH" || exit 1

    if [ -z "$GITEA_URL" ] || [ -z "$GITEA_TOKEN" ]; then
        echo "Error: Gitea not configured"
        return 1
    fi

    echo "Pushing to Gitea..."

    # Configure credential helper for this push
    local auth_url=$(echo "$GITEA_URL" | sed "s|://|://oauth2:${GITEA_TOKEN}@|")
    git remote set-url origin "${auth_url}/${GITEA_REPO}.git"

    git push -u origin "$GITEA_BRANCH" 2>&1
    local result=$?

    # Reset URL without token
    git remote set-url origin "${GITEA_URL}/${GITEA_REPO}.git"

    if [ $result -eq 0 ]; then
        echo "Successfully pushed to Gitea"
    else
        echo "Push failed (code: $result)"
    fi

    return $result
}

# Pull from Gitea
cmd_pull() {
    load_config
    cd "$VAULT_PATH" || exit 1

    echo "Pulling from Gitea..."

    local auth_url=$(echo "$GITEA_URL" | sed "s|://|://oauth2:${GITEA_TOKEN}@|")
    git remote set-url origin "${auth_url}/${GITEA_REPO}.git"

    git pull origin "$GITEA_BRANCH" 2>&1
    local result=$?

    git remote set-url origin "${GITEA_URL}/${GITEA_REPO}.git"

    return $result
}

# Restore module
cmd_restore() {
    local module="$1"

    load_config
    cd "$VAULT_PATH" || exit 1

    if [ -z "$module" ]; then
        echo "Usage: configvaultctl restore <module>"
        echo "Available modules:"
        ls -d */ 2>/dev/null | tr -d '/'
        return 1
    fi

    [ -d "$module" ] || { echo "Module not found: $module"; return 1; }

    echo "Restoring module: $module"
    echo "WARNING: This will overwrite current configurations!"
    echo ""

    # Restore UCI configs
    for uci_file in "$module/uci/"*; do
        [ -f "$uci_file" ] || continue
        local config=$(basename "$uci_file")
        echo "  Restoring /etc/config/$config"
        cp "$uci_file" "/etc/config/$config"
    done

    echo ""
    echo "Restored. Run 'reload_config' or reboot to apply changes."
}

# Export clone package
cmd_export_clone() {
    local output="${1:-/tmp/secubox-clone-$(date +%Y%m%d).tar.gz}"

    load_config

    # First do a backup
    cmd_backup

    cd "$VAULT_PATH" || exit 1

    echo "Creating clone package: $output"

    # Create clone manifest
    cat > clone-manifest.json << EOF
{
    "type": "secubox-clone",
    "version": "1.0",
    "created": "$(date -Iseconds)",
    "source": {
        "hostname": "$(uci -q get system.@system[0].hostname)",
        "model": "$(cat /tmp/sysinfo/model 2>/dev/null || echo 'unknown')",
        "version": "$(cat /etc/openwrt_release | grep DISTRIB_RELEASE | cut -d= -f2 | tr -d "'")"
    },
    "modules": [
$(ls -d */ 2>/dev/null | tr -d '/' | while read m; do echo "        \"$m\","; done | sed '$ s/,$//')
    ]
}
EOF

    # Create tarball
    tar -czf "$output" -C "$VAULT_PATH" .

    echo "Clone package created: $output"
    echo "Size: $(ls -lh "$output" | awk '{print $5}')"
}

# Import clone package
cmd_import_clone() {
    local archive="$1"
    local apply_flag="$2"

    [ -f "$archive" ] || { echo "File not found: $archive"; return 1; }

    load_config

    echo "Importing clone package: $archive"

    # Extract to vault
    mkdir -p "$VAULT_PATH"
    tar -xzf "$archive" -C "$VAULT_PATH"

    # Show manifest
    if [ -f "$VAULT_PATH/clone-manifest.json" ]; then
        echo ""
        echo "Clone source:"
        jsonfilter -i "$VAULT_PATH/clone-manifest.json" -e '@.source.hostname' | xargs echo "  Hostname:"
        jsonfilter -i "$VAULT_PATH/clone-manifest.json" -e '@.source.version' | xargs echo "  Version:"
    fi

    echo ""

    # Auto-apply if --apply flag is set
    if [ "$apply_flag" = "--apply" ] || [ "$apply_flag" = "-a" ]; then
        echo "Auto-applying all modules..."
        cmd_restore_all
        echo ""
        echo "Import and restore complete. Reboot recommended."
    else
        echo "Import complete. Use 'configvaultctl restore <module>' to apply configs."
        echo "Or use 'configvaultctl import-clone <file> --apply' to auto-restore all."
    fi
}

# Restore all modules (for auto-apply)
cmd_restore_all() {
    load_config
    cd "$VAULT_PATH" || exit 1

    echo "Restoring all modules..."
    echo ""

    local restored=0
    local failed=0

    for module_dir in */; do
        [ -d "$module_dir" ] || continue
        local module="${module_dir%/}"

        # Skip non-module directories
        [ "$module" = ".git" ] && continue

        if [ -d "$module/uci" ] && [ "$(ls -A "$module/uci" 2>/dev/null)" ]; then
            echo "[$module]"
            for uci_file in "$module/uci/"*; do
                [ -f "$uci_file" ] || continue
                local config=$(basename "$uci_file")
                echo "  Restoring /etc/config/$config"
                if cp "$uci_file" "/etc/config/$config" 2>/dev/null; then
                    restored=$((restored + 1))
                else
                    echo "  ✗ Failed to restore $config"
                    failed=$((failed + 1))
                fi
            done
        fi
    done

    echo ""
    echo "Restored: $restored configs, Failed: $failed"

    # Reload configs
    if [ $restored -gt 0 ]; then
        echo ""
        echo "Reloading configuration..."
        /etc/init.d/network reload 2>/dev/null || true
        /etc/init.d/system reload 2>/dev/null || true
    fi
}

#------------------------------------------------------------------------------
# Remote Provisioning
#------------------------------------------------------------------------------

# Provision remote node with clone
cmd_provision() {
    local target="$1"
    local clone_file="$2"

    [ -z "$target" ] && {
        echo "Usage: configvaultctl provision <node> [clone-file]"
        echo ""
        echo "Provision a remote SecuBox node with configuration clone."
        echo ""
        echo "Arguments:"
        echo "  node        Target node (IP, hostname, or 'all' for mesh)"
        echo "  clone-file  Optional pre-existing clone (creates new if not specified)"
        echo ""
        echo "Examples:"
        echo "  configvaultctl provision 192.168.255.2"
        echo "  configvaultctl provision sb-office /tmp/secubox-clone.tar.gz"
        echo "  configvaultctl provision all"
        return 1
    }

    # Check rttyctl is available
    command -v rttyctl >/dev/null || {
        echo "Error: rttyctl not found. Install secubox-app-rtty-remote."
        return 1
    }

    load_config

    # Create clone if not provided
    if [ -z "$clone_file" ] || [ ! -f "$clone_file" ]; then
        clone_file="/tmp/secubox-provision-$(date +%Y%m%d%H%M).tar.gz"
        echo "Creating configuration clone..."
        cmd_export_clone "$clone_file"
        echo ""
    fi

    [ -f "$clone_file" ] || { echo "Clone file not found: $clone_file"; return 1; }

    local clone_size=$(ls -lh "$clone_file" | awk '{print $5}')
    local clone_b64="/tmp/clone-b64-$$.txt"

    echo "Provisioning target: $target"
    echo "Clone package: $clone_file ($clone_size)"
    echo ""

    # Base64 encode for transfer
    base64 -w 0 "$clone_file" > "$clone_b64"

    if [ "$target" = "all" ]; then
        provision_all_nodes "$clone_b64"
    else
        provision_single_node "$target" "$clone_b64"
    fi

    rm -f "$clone_b64"
}

provision_single_node() {
    local node="$1"
    local clone_b64="$2"

    echo "Provisioning node: $node"

    # Check node is reachable
    local addr=$(rttyctl node "$node" 2>&1 | grep "Address:" | awk '{print $2}')
    [ -z "$addr" ] && addr="$node"

    if ! ping -c 1 -W 2 "$addr" >/dev/null 2>&1; then
        echo "  ✗ Node not reachable"
        return 1
    fi

    # Transfer clone via RPC (write to temp file on remote)
    echo "  Transferring clone package..."
    local remote_file="/tmp/secubox-clone-import.tar.gz"

    # Use file RPC to write the clone
    local clone_content=$(cat "$clone_b64")
    local write_result=$(rttyctl rpc "$node" "file" "write" \
        "{\"path\":\"$remote_file\",\"data\":\"$clone_content\",\"base64\":true}" 2>&1)

    if echo "$write_result" | grep -qi "error"; then
        # Fallback: use exec to decode and write
        echo "  Using fallback transfer method..."
        rttyctl rpc "$node" "file" "exec" \
            "{\"command\":\"echo '$clone_content' | base64 -d > $remote_file\"}" 2>/dev/null
    fi

    # Trigger import with auto-apply on remote
    echo "  Importing and applying configuration..."
    local import_result=$(rttyctl rpc "$node" "luci.config-vault" "import_apply" \
        "{\"archive\":\"$remote_file\"}" 2>&1)

    if echo "$import_result" | grep -qi "success.*true"; then
        echo "  ✓ Provisioning complete"
        echo ""
        echo "  Remote node will reboot to apply changes."
    else
        # Try direct command via luci.sys
        rttyctl rpc "$node" "luci" "setInitAction" \
            '{"name":"config-vault-apply","action":"start"}' 2>/dev/null

        echo "  ✓ Clone transferred, manual apply may be required"
    fi
}

provision_all_nodes() {
    local clone_b64="$1"

    echo "Provisioning ALL mesh nodes..."
    echo ""

    local success=0
    local failed=0

    # Get nodes from rttyctl
    local nodes=$(rttyctl json-nodes 2>/dev/null | jsonfilter -e '@.nodes[*].address' 2>/dev/null)

    for node in $nodes; do
        [ -z "$node" ] && continue

        # Skip local node
        local local_ip=$(uci -q get network.lan.ipaddr)
        case "$node" in
            127.0.0.1|localhost|$local_ip)
                echo "[$node] Skipping (local)"
                continue
                ;;
        esac

        echo "[$node]"
        if provision_single_node "$node" "$clone_b64"; then
            success=$((success + 1))
        else
            failed=$((failed + 1))
        fi
        echo ""
    done

    echo "Provisioning Summary: $success succeeded, $failed failed"
}

#------------------------------------------------------------------------------
# First-Boot Config Pull
#------------------------------------------------------------------------------

# Pull configuration from master node on first boot
cmd_pull_config() {
    local master_url="$1"
    local apply="${2:---apply}"

    [ -z "$master_url" ] && {
        echo "Usage: configvaultctl pull-config <master-url> [--apply]"
        echo ""
        echo "Pull configuration from master SecuBox node."
        echo "Used for first-boot provisioning of new devices."
        echo ""
        echo "Arguments:"
        echo "  master-url  URL or IP of master node (e.g., 192.168.255.1)"
        echo "  --apply     Auto-apply after pulling (default)"
        echo "  --no-apply  Just download, don't apply"
        echo ""
        echo "Examples:"
        echo "  configvaultctl pull-config 192.168.255.1"
        echo "  configvaultctl pull-config master.secubox.local --no-apply"
        echo ""
        echo "First-boot setup:"
        echo "  Add to /etc/rc.local:"
        echo "    [ -f /etc/secubox-provisioned ] || configvaultctl pull-config 192.168.255.1"
        return 1
    }

    load_config

    echo "Pulling configuration from master: $master_url"
    echo ""

    local clone_file="/tmp/secubox-clone-pulled.tar.gz"

    # Try to fetch clone via HTTP first (master serves it)
    local http_url="http://${master_url}/config-vault/clone.tar.gz"
    echo "Trying HTTP: $http_url"

    if curl -sf -m 30 -o "$clone_file" "$http_url" 2>/dev/null; then
        echo "  ✓ Downloaded via HTTP"
    else
        # Fallback: try RPC via rttyctl
        echo "  HTTP failed, trying RPC..."

        if command -v rttyctl >/dev/null; then
            local export_result=$(rttyctl rpc "$master_url" "luci.config-vault" "export_clone" '{}' 2>&1)
            local clone_b64=$(echo "$export_result" | jsonfilter -e '@.data' 2>/dev/null)

            if [ -n "$clone_b64" ]; then
                echo "$clone_b64" | base64 -d > "$clone_file"
                echo "  ✓ Downloaded via RPC"
            else
                echo "  ✗ Failed to fetch clone from master"
                return 1
            fi
        else
            echo "  ✗ No rttyctl available for RPC fallback"
            return 1
        fi
    fi

    # Verify archive
    if ! tar -tzf "$clone_file" >/dev/null 2>&1; then
        echo "Error: Invalid clone archive"
        rm -f "$clone_file"
        return 1
    fi

    # Import
    if [ "$apply" = "--no-apply" ]; then
        cmd_import_clone "$clone_file"
    else
        cmd_import_clone "$clone_file" --apply

        # Mark as provisioned
        echo "$(date -Iseconds) pulled from $master_url" > /etc/secubox-provisioned
        echo ""
        echo "Device marked as provisioned. Rebooting in 5 seconds..."
        sleep 5
        reboot
    fi
}

# Serve clone for HTTP pull (called by uhttpd CGI or cron)
cmd_serve_clone() {
    local output_dir="${1:-/www/config-vault}"

    load_config

    mkdir -p "$output_dir"

    # Create fresh clone
    local clone_file="$output_dir/clone.tar.gz"
    cmd_export_clone "$clone_file" >/dev/null 2>&1

    # Create metadata
    cat > "$output_dir/manifest.json" << EOF
{
    "hostname": "$(uci -q get system.@system[0].hostname)",
    "updated": "$(date -Iseconds)",
    "size": $(stat -c%s "$clone_file" 2>/dev/null || echo 0),
    "modules": $(ls -d "$VAULT_PATH"/*/ 2>/dev/null | wc -l)
}
EOF

    echo "Clone served at: $output_dir/clone.tar.gz"
}

# Show status
cmd_status() {
    load_config

    echo "SecuBox Configuration Vault"
    echo "==========================="
    echo ""
    echo "Vault Path: $VAULT_PATH"
    echo "Auto-commit: $AUTO_COMMIT"
    echo "Auto-push: $AUTO_PUSH"
    echo ""

    if [ -d "$VAULT_PATH/.git" ]; then
        cd "$VAULT_PATH"
        echo "Git Status:"
        echo "  Branch: $(git branch --show-current 2>/dev/null || echo 'unknown')"
        echo "  Remote: $(git remote get-url origin 2>/dev/null || echo 'not configured')"
        echo "  Last commit: $(git log -1 --format='%h %s' 2>/dev/null || echo 'none')"
        echo "  Changes: $(git status --porcelain 2>/dev/null | wc -l) uncommitted"
        echo ""

        echo "Modules:"
        config_load config-vault
        config_foreach show_module_status module
    else
        echo "Vault not initialized. Run: configvaultctl init"
    fi
}

show_module_status() {
    local section="$1"
    local enabled description

    config_get enabled "$section" enabled "1"
    config_get description "$section" description "$section"

    local status="disabled"
    [ "$enabled" = "1" ] && status="enabled"

    local files=0
    [ -d "$VAULT_PATH/$section" ] && files=$(find "$VAULT_PATH/$section" -type f | wc -l)

    printf "  %-12s %-8s %3d files  %s\n" "$section" "[$status]" "$files" "$description"
}

# Show history/changelog
cmd_history() {
    local count="${1:-20}"

    load_config
    cd "$VAULT_PATH" || exit 1

    echo "Configuration Change History"
    echo "============================"
    echo ""

    git log --oneline -n "$count" --date=short --format="%h %ad %s"
}

# Show diff since last commit
cmd_diff() {
    load_config
    cd "$VAULT_PATH" || exit 1

    git diff
}

# Track a LuCI config change (called by hook)
cmd_track() {
    local config="$1"
    local action="${2:-modified}"
    local user="${3:-system}"

    load_config

    # Find which module this config belongs to
    local module=""
    config_load config-vault

    find_module_for_config() {
        local section="$1"
        config_list_foreach "$section" config check_config_match "$config" "$section"
    }

    check_config_match() {
        local cfg="$1"
        local target="$2"
        local mod="$3"
        [ "$cfg" = "$target" ] && module="$mod"
    }

    config_foreach find_module_for_config module

    [ -z "$module" ] && return 0  # Config not tracked

    # Backup the changed config
    backup_uci_config "$config" "$module"

    # Commit the change
    cd "$VAULT_PATH" || return 1

    git add -A
    git commit -m "LuCI change: $config ($action)

Module: $module
Config: $config
Action: $action
User: $user
Time: $(date -Iseconds)" 2>/dev/null

    # Auto-push if enabled
    [ "$AUTO_PUSH" = "1" ] && [ -n "$GITEA_URL" ] && cmd_push >/dev/null 2>&1 &
}

# List available modules
cmd_modules() {
    load_config

    echo "Configured Modules:"
    echo ""

    config_load config-vault
    config_foreach list_module module
}

list_module() {
    local section="$1"
    local enabled description

    config_get enabled "$section" enabled "1"
    config_get description "$section" description ""

    printf "%-12s " "$section"
    [ "$enabled" = "1" ] && printf "[enabled] " || printf "[disabled]"
    echo "$description"

    # List configs
    config_list_foreach "$section" config list_config_item
    echo ""
}

list_config_item() {
    local config="$1"
    local exists=""
    [ -f "/etc/config/$config" ] && exists="*" || exists=" "
    echo "    $exists $config"
}

# Usage
usage() {
    cat << EOF
SecuBox Configuration Vault - Versioned config management

USAGE:
    configvaultctl <command> [options]

COMMANDS:
    init                   Initialize vault repository
    backup [module]        Backup configs (all or specific module)
    restore <module>       Restore module configs from vault
    restore-all            Restore ALL modules from vault
    push                   Push changes to Gitea
    pull                   Pull latest from Gitea
    status                 Show vault status
    history [n]            Show last n config changes (default: 20)
    diff                   Show uncommitted changes
    modules                List configured modules
    track <config>         Track a config change (used by hooks)
    export-clone [file]    Create deployment clone package
    import-clone <file> [--apply]  Import clone (--apply to auto-restore)

DEVICE PROVISIONING:
    provision <node> [file]    Push clone to remote node and apply
    pull-config <master>       Pull config from master (first-boot)
    serve-clone [dir]          Generate clone for HTTP serving

EXAMPLES:
    # Initialize and backup all
    configvaultctl init
    configvaultctl backup

    # Create clone for new device
    configvaultctl export-clone /tmp/secubox-v1.tar.gz

    # Import and auto-apply on new device
    configvaultctl import-clone /tmp/secubox-v1.tar.gz --apply

    # Remote provisioning
    configvaultctl provision 192.168.255.2
    configvaultctl provision all

    # First-boot pull from master
    configvaultctl pull-config 192.168.255.1

AUDIT TRAIL:
    All changes are versioned with git for certification compliance.
    View history: configvaultctl history
EOF
}

# Main
case "$1" in
    init)
        cmd_init
        ;;
    backup)
        cmd_backup "$2"
        ;;
    restore)
        cmd_restore "$2"
        ;;
    restore-all)
        cmd_restore_all
        ;;
    push)
        cmd_push
        ;;
    pull)
        cmd_pull
        ;;
    status)
        cmd_status
        ;;
    history)
        cmd_history "$2"
        ;;
    diff)
        cmd_diff
        ;;
    modules)
        cmd_modules
        ;;
    track)
        cmd_track "$2" "$3" "$4"
        ;;
    export-clone|export)
        cmd_export_clone "$2"
        ;;
    import-clone|import)
        cmd_import_clone "$2" "$3"
        ;;
    provision)
        cmd_provision "$2" "$3"
        ;;
    pull-config)
        cmd_pull_config "$2" "$3"
        ;;
    serve-clone|serve)
        cmd_serve_clone "$2"
        ;;
    *)
        usage
        ;;
esac
