#!/usr/bin/env bash
set -euo pipefail

###############################################################################
# SYNC — Commit and push all ~/content/ repos
#
# Maintainer:   Kris Yotam <krisyotam@pm.me>
# License:      MIT
# Created:      2026-02-15
# Description:  Walks each git repo in ~/content/, stages changes, commits,
#               and pushes. If a commit or push fails, invokes headless Claude
#               to diagnose and fix the issue. Designed to be called by git.js
#               before committing the main site repo.
#
# Usage:
#   sync              # sync all content repos
#   sync --quiet      # suppress per-repo output (for git.js integration)
###############################################################################

CONTENT_DIR="$HOME/content"
CONTENT_TYPES=(blog diary essays fiction news notes ocs papers progymnasmata reviews verse)

QUIET=false
[[ "${1:-}" == "--quiet" ]] && QUIET=true

log() { $QUIET || echo "$@"; }

###############################################################################
# sync a single repo
###############################################################################

sync_repo() {
    local type="$1"
    local repo="$CONTENT_DIR/$type"

    # Skip if not a git repo
    [[ -d "$repo/.git" ]] || return 0

    cd "$repo"

    # Check for changes
    if git diff --quiet HEAD -- 2>/dev/null && [[ -z "$(git ls-files --others --exclude-standard)" ]]; then
        log "  $type: clean"
        return 0
    fi

    log "  $type: changes detected, committing..."

    # Stage all changes
    if ! git add -A 2>/dev/null; then
        log "  $type: ERROR staging files"
        attempt_fix "$type" "git add -A failed in $repo"
        return $?
    fi

    # Commit with date-stamped message
    local date
    date="$(date +%Y-%m-%d)"
    local msg="content update $date"

    if ! git commit -m "$msg" 2>/dev/null; then
        log "  $type: ERROR committing"
        attempt_fix "$type" "git commit failed in $repo"
        return $?
    fi

    # Push
    if ! git push origin HEAD 2>/dev/null; then
        log "  $type: ERROR pushing, retrying..."
        # Try pull --rebase then push
        if git pull --rebase origin main 2>/dev/null && git push origin HEAD 2>/dev/null; then
            log "  $type: pushed after rebase"
        else
            log "  $type: push failed, invoking Claude..."
            attempt_fix "$type" "git push failed in $repo after rebase attempt"
            return $?
        fi
    fi

    log "  $type: synced"
    return 0
}

###############################################################################
# claude error recovery
###############################################################################

attempt_fix() {
    local type="$1"
    local error_desc="$2"
    local repo="$CONTENT_DIR/$type"

    if ! command -v claude >/dev/null 2>&1; then
        echo "  $type: FAILED — claude CLI not available for auto-fix"
        return 1
    fi

    local instruction="A git error occurred in the content repo at $repo.

Error: $error_desc

Current state:
$(cd "$repo" && git status 2>&1)

Recent log:
$(cd "$repo" && git log --oneline -5 2>&1)

Fix this git issue so the repo can be committed and pushed to origin. The repo contains .mdx content files — do not delete any content. Common fixes:
- If merge conflict: resolve by keeping both changes
- If push rejected: pull --rebase then push
- If dirty index: stage and commit
- If detached HEAD: checkout main and merge

Run the necessary git commands in $repo to fix the issue, then commit and push."

    log "  $type: invoking Claude for auto-fix..."

    if claude -p "$instruction" --allowedTools "Bash(git *)" 2>/dev/null; then
        log "  $type: Claude fix succeeded"
        return 0
    else
        echo "  $type: FAILED — Claude could not fix the issue"
        return 1
    fi
}

###############################################################################
# main
###############################################################################

log "Syncing content repos..."

failed=0
synced=0
clean=0

for type in "${CONTENT_TYPES[@]}"; do
    repo="$CONTENT_DIR/$type"
    [[ -d "$repo/.git" ]] || continue

    if sync_repo "$type"; then
        # Check if it was clean or synced
        cd "$repo"
        if git diff --quiet HEAD -- 2>/dev/null && [[ -z "$(git ls-files --others --exclude-standard)" ]]; then
            clean=$((clean + 1))
        else
            synced=$((synced + 1))
        fi
    else
        failed=$((failed + 1))
    fi
done

log ""
if [[ $failed -gt 0 ]]; then
    echo "Sync complete: $failed repo(s) failed"
    exit 1
else
    log "Sync complete: all repos clean/synced"
    exit 0
fi
