#!/usr/bin/env bash
# scripts/brand/sync-upstream.sh — pull the shared codebase into this fork.
#
# This fork is petav3 plus a brand layer. Upstream owns the product; this repo
# owns only what scripts/brand/brand.conf and resources/css/app.css say.
#
# The one judgement call in a sync is a conflicted file, and the script makes it
# the same way every time: it rebuilds what the fork's own version WOULD be if
# the only thing the fork ever did to that file was rebrand it. If that matches
# the fork's actual version, the fork has no real change there and upstream's
# version (rebranded) is taken automatically. If it does not match, the fork
# genuinely edited that file and a human has to look — so the script stops
# rather than guessing.
#
# Usage: bash scripts/brand/sync-upstream.sh [upstream-branch]   (default master)
# Then:  bash scripts/live-build.sh --force && npx vitest run && git push
set -euo pipefail

HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$(git rev-parse --show-toplevel)"
BRANCH="${1:-master}"
UPSTREAM_URL="git@github.com:property-lab/petav3.git"

git remote get-url upstream >/dev/null 2>&1 || git remote add upstream "$UPSTREAM_URL"
echo "==> fetching upstream"
git fetch --no-tags upstream "$BRANCH"

read -r AHEAD BEHIND < <(git rev-list --left-right --count "HEAD...upstream/$BRANCH" | tr '\t' ' ')
echo "==> this fork is $AHEAD ahead, $BEHIND behind upstream/$BRANCH"
[ "$BEHIND" -eq 0 ] && { echo "already up to date"; exit 0; }

[ -z "$(git status --porcelain)" ] || { echo "working tree is dirty — commit or stash first"; exit 1; }
SYNC_BRANCH="sync/upstream-$(date +%Y%m%d-%H%M)"
git switch -c "$SYNC_BRANCH"
echo "==> merging on branch $SYNC_BRANCH"
git merge --no-commit --no-ff "upstream/$BRANCH" || true

TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
AUTO=(); MANUAL=()
while IFS= read -r f; do
    [ -n "$f" ] || continue
    if git show ":1:$f" > "$TMP/base" 2>/dev/null && git show ":2:$f" > "$TMP/ours" 2>/dev/null; then
        bash "$HERE/brandize.sh" "$TMP/base" >/dev/null
        if cmp -s "$TMP/base" "$TMP/ours"; then
            git checkout --theirs -- "$f"
            bash "$HERE/brandize.sh" "$f" >/dev/null
            git add -- "$f"; AUTO+=("$f"); continue
        fi
    fi
    MANUAL+=("$f")
done < <(git diff --name-only --diff-filter=U)

echo "==> re-applying the brand layer to everything upstream just brought in"
bash "$HERE/brandize.sh"
git add -A

echo
echo "===================== SYNC REPORT ====================="
echo "auto-resolved (fork had only rebranded these): ${#AUTO[@]}"
printf '    %s\n' "${AUTO[@]:-}" | sed '/^    $/d'
echo "NEEDS A HUMAN (fork really changed these):     ${#MANUAL[@]}"
printf '    %s\n' "${MANUAL[@]:-}" | sed '/^    $/d'
echo
echo "leak check — should both be 0:"
printf '    upstream colours left: %s\n' \
  "$(git grep -IohE '\b(bg|text|border|ring|from|via|to|fill|stroke)-(blue|indigo|sky)-[0-9]{2,3}\b' -- resources/js | wc -l)"
# Lines the sweep deliberately keeps (brand.conf KEEP_PHRASES, `brand:keep`)
# are not leaks — strip them before counting, or this never reads 0 again.
# shellcheck disable=SC1090
source "$HERE/brand.conf"
printf '    upstream brand name left (outside class names, keep-list aside): %s\n' \
  "$(git grep -InP '(?<![A-Za-z_])PropertyLab(?![A-Za-z_])' -- app config resources routes src \
       | grep -v 'brand:keep' \
       | KEEP="$(printf '%s\n' ${KEEP_PHRASES[@]+"${KEEP_PHRASES[@]}"})" perl -ne '
           BEGIN { $k = join "|", map { quotemeta } grep { length } split /\n/, $ENV{KEEP}; }
           s/(?:$k)//g if length $k; print if /(?<![A-Za-z_])PropertyLab(?![A-Za-z_])/' \
       | wc -l | tr -d ' ')"
echo "======================================================="
echo
if [ ${#MANUAL[@]} -gt 0 ]; then
    echo "STOP: resolve the files above by hand, then:  git add -A && git commit"
    exit 1
fi
echo "Next:  bash scripts/live-build.sh --force  &&  npx vitest run"
echo "Then:  git commit  &&  git push -u origin $SYNC_BRANCH"
