#!/usr/bin/env bash
# ssr-update — pull the latest ssr code from origin and refresh side-effects.
#
# Behavior:
#   1. Verify the repo is a clean git checkout on a real branch.
#   2. git fetch + fast-forward pull. Bail if FF would be impossible.
#   3. Report VERSION delta.
#   4. If the launchd template or any bin/ file changed and the schedule is
#      currently active, re-render and reload it.
#   5. If config/ssr.conf.example gained new keys, warn the user.

set -euo pipefail
SSR_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
# shellcheck source=../lib/common.sh
source "$SSR_ROOT/lib/common.sh"

DRY_RUN=false
while [[ $# -gt 0 ]]; do
    case "$1" in
        -n|--dry-run) DRY_RUN=true; shift ;;
        -h|--help)
            cat <<EOF
Usage: ssr update [--dry-run]

Pulls the latest commit on the current branch and re-applies side effects:
- Re-renders & reloads the launchd plist if it changed (when schedule is active).
- Reports added config keys in config/ssr.conf.example.
EOF
            exit 0 ;;
        *) ssr::die "Unknown flag: $1" ;;
    esac
done

ssr::require_cmd git

# --- 1. preflight ---------------------------------------------------------
[[ -d "$SSR_ROOT/.git" ]] \
    || ssr::die "Not a git checkout: $SSR_ROOT (re-clone the repo to enable updates)"

cd "$SSR_ROOT"

branch="$(git symbolic-ref --quiet --short HEAD 2>/dev/null || true)"
[[ -n "$branch" ]] || ssr::die "Detached HEAD — checkout a branch first"

if [[ -n "$(git status --porcelain)" ]]; then
    ssr::die "Working tree has local changes — commit, stash, or revert before updating"
fi

origin_url="$(git remote get-url origin 2>/dev/null || true)"
[[ -n "$origin_url" ]] || ssr::die "No 'origin' remote configured"
ssr::log "Updating from $origin_url ($branch)"

# --- 2. fetch + ff pull ---------------------------------------------------
old_sha="$(git rev-parse HEAD)"
old_version="$(cat VERSION 2>/dev/null || echo unknown)"

if $DRY_RUN; then
    git fetch --quiet origin "$branch"
    new_sha="$(git rev-parse "origin/$branch")"
else
    git fetch --quiet origin "$branch"
    new_sha="$(git rev-parse "origin/$branch")"
    if [[ "$old_sha" == "$new_sha" ]]; then
        ssr::ok "Already up to date ($(git rev-parse --short HEAD))"
        exit 0
    fi
    if ! git merge-base --is-ancestor "$old_sha" "$new_sha"; then
        ssr::die "Cannot fast-forward (history diverged). Resolve manually: git pull --rebase"
    fi
    git merge --ff-only --quiet "origin/$branch"
fi

new_version="$(cat VERSION 2>/dev/null || echo unknown)"

if [[ "$old_sha" == "$new_sha" ]]; then
    ssr::ok "No changes available."
    exit 0
fi

# --- 3. summarize -----------------------------------------------------
ssr::ok "Updated $(git rev-parse --short "$old_sha") → $(git rev-parse --short "$new_sha")"
if [[ "$old_version" != "$new_version" ]]; then
    ssr::log "Version: $old_version → $new_version"
fi
ssr::log "Changes:"
git --no-pager log --oneline "$old_sha..$new_sha" | sed 's/^/  /'

$DRY_RUN && { ssr::log "(dry-run: no side effects executed)"; exit 0; }

# --- 4. launchd refresh -----------------------------------------------
changed_files="$(git --no-pager diff --name-only "$old_sha" "$new_sha")"
plist_changed=false
case "$changed_files" in
    *launchd/*|*bin/ssr*) plist_changed=true ;;
esac

label="${SSR_LAUNCHD_LABEL:-de.surke.ssr.sync}"
if $plist_changed && launchctl list 2>/dev/null | grep -q "$label"; then
    ssr::log "launchd-relevant files changed → reloading schedule"
    "$SSR_ROOT/bin/ssr-schedule" on
fi

# --- 5. config drift hint -------------------------------------------------
example="$SSR_ROOT/config/ssr.conf.example"
user_cfg="${SSR_CONFIG:-$HOME/.config/ssr/ssr.conf}"
if [[ -f "$user_cfg" && -f "$example" ]]; then
    new_keys="$(comm -23 \
        <(grep -E '^[A-Z_][A-Z0-9_]*=' "$example" | cut -d= -f1 | sort -u) \
        <(grep -E '^[A-Z_][A-Z0-9_]*=' "$user_cfg" | cut -d= -f1 | sort -u))"
    if [[ -n "$new_keys" ]]; then
        ssr::warn "New config keys available in $example:"
        echo "$new_keys" | sed 's/^/  /'
        echo "Review with:  ssr config edit"
    fi
fi

ssr::ok "Update complete."
