#!/bin/bash
# OpenClaw CLI - Manage your openclaw-config installation

OPENCLAW_CACHE="${HOME}/.openclaw"
OPENCLAW_REPO="${OPENCLAW_CACHE}/repo"
OPENCLAW_DIR="${OPENCLAW_DIR:-$HOME/openclaw}"

# User-owned workflow files that must never be overwritten during sync
USER_OWNED_FILES="rules.md agent_notes.md preferences.md processed.md"
USER_OWNED_DIRS="logs"

usage() {
    cat <<EOF
OpenClaw CLI - Manage your openclaw-config installation

Commands:
  version              Show installed version
  status               Check for updates
  sync [--force]       Sync updates from upstream
  diff                 Show differences with upstream
  add-skill <name>     Add a skill from the repo
  upgrade              Full upgrade with backup
  help                 Show this help

Options (for sync):
  --force              Overwrite local changes
  --dry-run            Show what would change
  --skills             Only sync skills
  --templates          Only sync templates
  --workflows          Only sync workflows

Examples:
  openclaw version
  openclaw sync --dry-run
  openclaw add-skill limitless
EOF
}

check_installed() {
    if [ ! -d "$OPENCLAW_REPO" ]; then
        echo "❌ OpenClaw not installed."
        echo ""
        echo "Run the bootstrap script:"
        echo "curl -fsSL https://raw.githubusercontent.com/TechNickAI/openclaw-config/main/scripts/bootstrap.sh | bash"
        exit 1
    fi
}

cmd_version() {
    if [ -f "$OPENCLAW_CACHE/installed-version" ]; then
        echo "Installed: $(cat "$OPENCLAW_CACHE/installed-version")"
    else
        echo "Installed: unknown"
    fi
    if [ -f "$OPENCLAW_REPO/VERSION" ]; then
        echo "Repo:      $(cat "$OPENCLAW_REPO/VERSION")"
    fi
}

cmd_status() {
    check_installed
    local installed="unknown"
    if [ -f "$OPENCLAW_CACHE/installed-version" ]; then
        installed=$(cat "$OPENCLAW_CACHE/installed-version")
    fi
    local remote="unknown"
    if [ -d "$OPENCLAW_REPO/.git" ]; then
        git -C "$OPENCLAW_REPO" fetch --quiet 2>/dev/null
        remote=$(git -C "$OPENCLAW_REPO" show origin/main:VERSION 2>/dev/null) \
            || remote=$(cat "$OPENCLAW_REPO/VERSION" 2>/dev/null) \
            || remote="unknown"
    elif [ -f "$OPENCLAW_REPO/VERSION" ]; then
        remote=$(cat "$OPENCLAW_REPO/VERSION")
    fi
    echo "Installed: $installed"
    echo "Available: $remote"
    if [ "$installed" = "$remote" ]; then
        echo "✓ Up to date"
    else
        echo "⬆ Update available — run: openclaw upgrade"
    fi
}

is_user_owned() {
    local file="$1"
    local base=$(basename "$file")
    # Only match user-owned files at the root level of the workflow directory
    for uf in $USER_OWNED_FILES; do
        [ "$file" = "$uf" ] && return 0
    done
    for ud in $USER_OWNED_DIRS; do
        # Match paths starting with the dir (logs/foo.md) or containing it (/logs/)
        case "$file" in
            "$ud/"*|*"/$ud/"*) return 0 ;;
        esac
        [ "$base" = "$ud" ] && return 0
    done
    return 1
}

cmd_sync() {
    check_installed

    local force=false dry_run=false only_skills=false only_templates=false only_workflows=false
    for arg in "$@"; do
        case "$arg" in
            --force) force=true ;;
            --dry-run) dry_run=true ;;
            --skills) only_skills=true ;;
            --templates) only_templates=true ;;
            --workflows) only_workflows=true ;;
        esac
    done

    local changed=0

    # Positive filter: if no filter flags, sync everything; otherwise only the flagged sections
    local sync_all=true
    if $only_skills || $only_templates || $only_workflows; then
        sync_all=false
    fi
    # If all three partial flags are set, it's functionally a full sync
    if $only_skills && $only_templates && $only_workflows; then
        sync_all=true
    fi

    # Sync templates
    if $sync_all || $only_templates; then
        for file in AGENTS.md HEARTBEAT.md; do
            if [ -f "$OPENCLAW_REPO/templates/$file" ]; then
                if [ ! -f "$OPENCLAW_DIR/$file" ] || $force; then
                    if $dry_run; then
                        echo "[dry-run] Would sync template: $file"
                    else
                        cp "$OPENCLAW_REPO/templates/$file" "$OPENCLAW_DIR/$file"
                        echo "✓ Synced template: $file"
                    fi
                    changed=$((changed + 1))
                else
                    echo "⚠ Skipping $file (may be customized, use --force to overwrite)"
                fi
            fi
        done
    fi

    # Sync skills
    if $sync_all || $only_skills; then
        for skill_dir in "$OPENCLAW_REPO/skills/"*/; do
            local skill=$(basename "$skill_dir")
            if [ -d "$OPENCLAW_DIR/skills/$skill" ]; then
                if $dry_run; then
                    echo "[dry-run] Would sync skill: $skill"
                else
                    cp -r "$skill_dir"* "$OPENCLAW_DIR/skills/$skill/"
                    chmod +x "$OPENCLAW_DIR/skills/$skill/$skill" 2>/dev/null || true
                    echo "✓ Synced skill: $skill"
                fi
                changed=$((changed + 1))
            fi
        done
    fi

    # Sync workflows (upstream-owned files only)
    if $sync_all || $only_workflows; then
        for wf_dir in "$OPENCLAW_REPO/workflows/"*/; do
            local wf=$(basename "$wf_dir")
            if [ -d "$OPENCLAW_DIR/workflows/$wf" ]; then
                # Find all files in the upstream workflow directory
                while IFS= read -r rel_path; do
                    if ! is_user_owned "$rel_path"; then
                        local dest="$OPENCLAW_DIR/workflows/$wf/$rel_path"
                        if $dry_run; then
                            echo "[dry-run] Would sync workflow file: workflows/$wf/$rel_path"
                        else
                            mkdir -p "$(dirname "$dest")"
                            cp "$wf_dir$rel_path" "$dest"
                            echo "✓ Synced workflow file: workflows/$wf/$rel_path"
                        fi
                        changed=$((changed + 1))
                    fi
                done < <(cd "$wf_dir" && find . -type f | sed 's|^\./||')
            fi
        done
    fi

    if [ $changed -eq 0 ]; then
        echo "✓ Everything up to date"
    fi

    # Only update installed version on full sync (partial sync leaves other categories stale)
    if ! $dry_run && $sync_all && [ -f "$OPENCLAW_REPO/VERSION" ]; then
        cp "$OPENCLAW_REPO/VERSION" "$OPENCLAW_CACHE/installed-version"
    fi
}

cmd_diff() {
    check_installed

    echo "📄 Differences between your files and upstream:"
    echo ""

    local found_diff=false

    # Templates
    for file in AGENTS.md HEARTBEAT.md; do
        if [ -f "$OPENCLAW_DIR/$file" ] && [ -f "$OPENCLAW_REPO/templates/$file" ]; then
            if ! diff -q "$OPENCLAW_DIR/$file" "$OPENCLAW_REPO/templates/$file" > /dev/null 2>&1; then
                echo "--- $file ---"
                diff -u "$OPENCLAW_DIR/$file" "$OPENCLAW_REPO/templates/$file" | head -50
                echo ""
                found_diff=true
            fi
        fi
    done

    # Skills (all installed skills, not hardcoded list)
    for skill_dir in "$OPENCLAW_REPO/skills/"*/; do
        local skill=$(basename "$skill_dir")
        if [ -d "$OPENCLAW_DIR/skills/$skill" ]; then
            for remote_file in "$skill_dir"*; do
                local base=$(basename "$remote_file")
                local local_file="$OPENCLAW_DIR/skills/$skill/$base"
                if [ -f "$local_file" ] && [ -f "$remote_file" ]; then
                    if ! diff -q "$local_file" "$remote_file" > /dev/null 2>&1; then
                        echo "--- skills/$skill/$base ---"
                        diff -u "$local_file" "$remote_file" | head -30
                        echo ""
                        found_diff=true
                    fi
                fi
            done
        fi
    done

    # Workflows (upstream-owned files only)
    for wf_dir in "$OPENCLAW_REPO/workflows/"*/; do
        local wf=$(basename "$wf_dir")
        if [ -d "$OPENCLAW_DIR/workflows/$wf" ]; then
            while IFS= read -r rel_path; do
                if ! is_user_owned "$rel_path"; then
                    local local_file="$OPENCLAW_DIR/workflows/$wf/$rel_path"
                    local remote_file="$wf_dir$rel_path"
                    if [ -f "$local_file" ]; then
                        if ! diff -q "$local_file" "$remote_file" > /dev/null 2>&1; then
                            echo "--- workflows/$wf/$rel_path ---"
                            diff -u "$local_file" "$remote_file" | head -30
                            echo ""
                            found_diff=true
                        fi
                    else
                        echo "--- workflows/$wf/$rel_path (new upstream file) ---"
                        echo ""
                        found_diff=true
                    fi
                fi
            done < <(cd "$wf_dir" && find . -type f | sed 's|^\./||')
        fi
    done

    if ! $found_diff; then
        echo "✓ No differences found"
    fi
}

cmd_add_skill() {
    check_installed

    local skill="$1"
    if [ -z "$skill" ]; then
        echo "Usage: openclaw add-skill <name>"
        echo ""
        echo "Available skills:"
        ls -1 "$OPENCLAW_REPO/skills/"
        exit 1
    fi

    if [ ! -d "$OPENCLAW_REPO/skills/$skill" ]; then
        echo "❌ Skill not found: $skill"
        echo ""
        echo "Available skills:"
        ls -1 "$OPENCLAW_REPO/skills/"
        exit 1
    fi

    mkdir -p "$OPENCLAW_DIR/skills/$skill"
    cp -r "$OPENCLAW_REPO/skills/$skill/"* "$OPENCLAW_DIR/skills/$skill/"
    chmod +x "$OPENCLAW_DIR/skills/$skill/$skill" 2>/dev/null || true

    echo "✓ Installed skill: $skill"
}

cmd_upgrade() {
    check_installed

    echo "🔄 OpenClaw Upgrade"
    echo ""

    # Create backup
    BACKUP_DIR="$OPENCLAW_CACHE/backups/$(date +%Y%m%d-%H%M%S)"
    mkdir -p "$BACKUP_DIR"

    echo "📦 Creating backup..."
    for file in AGENTS.md SOUL.md USER.md TOOLS.md HEARTBEAT.md MEMORY.md; do
        if [ -f "$OPENCLAW_DIR/$file" ]; then
            cp "$OPENCLAW_DIR/$file" "$BACKUP_DIR/"
        fi
    done
    if [ -d "$OPENCLAW_DIR/memory" ]; then
        cp -r "$OPENCLAW_DIR/memory" "$BACKUP_DIR/"
    fi
    if [ -d "$OPENCLAW_DIR/workflows" ]; then
        cp -r "$OPENCLAW_DIR/workflows" "$BACKUP_DIR/"
    fi
    echo "✓ Backup created: $BACKUP_DIR"
    echo ""

    # Pull latest from upstream
    echo "📥 Pulling latest..."
    (cd "$OPENCLAW_REPO" && git pull --ff-only 2>&1) || {
        echo "❌ Failed to pull upstream. Check ~/.openclaw/repo for conflicts."
        exit 1
    }

    # Force sync
    cmd_sync --force

    echo ""
    echo "✓ Upgrade complete!"
    echo "   Backup at: $BACKUP_DIR"
}

# Main
case "${1:-help}" in
    version|v)
        cmd_version
        ;;
    status|s)
        cmd_status
        ;;
    sync)
        shift
        cmd_sync "$@"
        ;;
    diff|d)
        cmd_diff
        ;;
    add-skill|add)
        shift
        cmd_add_skill "$@"
        ;;
    upgrade|u)
        cmd_upgrade
        ;;
    help|h|--help|-h)
        usage
        ;;
    *)
        echo "Unknown command: $1"
        echo ""
        usage
        exit 1
        ;;
esac
