#!/usr/bin/env bash
# Deploy this app to production with the latest boboko-core tag.
#
#   1. Refuses to run with uncommitted work (the server deploys what's pushed,
#      nothing else) — only the core wiring files are allowed to be dirty.
#   2. Pulls translation lines added in the Language Lines UI into core's
#      seeders (boboko:translations:pull) — in local mode; if any are pulled,
#      stops so you can release core first. In repo mode it only checks.
#   3. Switches to repo mode if you're on the local ../boboko-core checkout,
#      and restarts the stack either way so the lockfiles pick up the newest
#      tag (bin/core-mode repo).
#   4. Commits the lockfile bump, if any, asks for confirmation, pushes.
#   5. Runs `envoy run deploy` (see Envoy.blade.php) against .env.envoy's host.
#
# Leaves you in repo mode — run `bin/core-mode local` to go back.
set -euo pipefail

cd "$(dirname "$0")/.."

fail() { echo "!!! $*" >&2; exit 1; }

[ -f .env.envoy ] || fail ".env.envoy not found — copy .env.envoy.example and fill it in."
branch=$(grep -m1 '^DEPLOY_BRANCH=' .env.envoy | cut -d= -f2-)
host=$(grep -m1 '^DEPLOY_SSH_HOST=' .env.envoy | cut -d= -f2-)
branch=${branch:-master}

[ "$(git branch --show-current)" = "$branch" ] || fail "You're not on $branch (the branch Envoy deploys)."

# Anything tracked and modified other than the four core wiring files would be
# silently left out of the deploy — make that a hard stop instead.
dirty=$(git status --porcelain --untracked-files=no |
    grep -vE '^.. (composer\.json|composer\.lock|package\.json|package-lock\.json)$' || true)
if [ -n "$dirty" ]; then
    echo "$dirty"
    fail "Commit or stash these first — the server only deploys what's pushed."
fi

echo ">>> Fetching origin..."
git fetch origin "$branch"
[ "$(git rev-list --count "HEAD..origin/$branch")" -eq 0 ] || fail "origin/$branch has commits you don't — pull first."

# Translation lines added through the Language Lines UI only reach other apps
# once they're in core's seeders. In local mode, pull them into
# ../boboko-core; in repo mode the command can only report them.
lines_in() { printf '%s\n' "$1" | sed -n 's/^\([0-9][0-9]*\) line(s).*/\1/p' | tail -1; }

if [ "$(bin/core-mode)" = local ]; then
    echo ">>> Pulling UI-added translations into ../boboko-core's seeders..."
    out=$(bin/dc-core.sh exec -T app php artisan boboko:translations:pull --no-ansi) ||
        fail "boboko:translations:pull failed — is the stack running (bin/dc-core.sh up -d)?"
    echo "$out"
    pulled=$(lines_in "$out")
    if [ "${pulled:-0}" -gt 0 ]; then
        fail "Pulled $pulled translation line(s) into ../boboko-core. Review, commit, tag and push core, then rerun bin/deploy."
    fi
else
    echo ">>> Checking for UI-added translations missing from core's seeders..."
    if out=$(bin/dc exec -T app php artisan boboko:translations:pull --dry-run --no-ansi 2>&1); then
        missing=$(lines_in "$out")
        if [ "${missing:-0}" -gt 0 ]; then
            echo "$out"
            fail "These lines are only in this database — run bin/core-mode local and rerun bin/deploy to pull them into core."
        fi
        echo "    nothing missing"
    else
        echo "    skipped — the installed boboko/core doesn't have boboko:translations:pull yet"
    fi
fi

# Switch to repo mode (or just restart if already there) so both lockfiles
# resolve the newest boboko-core tag.
bin/core-mode repo

git diff --quiet HEAD -- composer.json package.json ||
    fail "composer.json / package.json differ from HEAD in repo mode — they should only differ by the local/repo toggle."
if grep -A14 '"name": "boboko/core"' composer.lock | grep -q '"type": "path"'; then
    fail "composer.lock still points boboko/core at the local path repo."
fi
if grep -A6 '"node_modules/@boboko/core": {' package-lock.json | grep -q '"link": true'; then
    fail "package-lock.json still links @boboko/core to the local checkout."
fi

version=$(grep -A1 '"name": "boboko/core"' composer.lock | grep -o '"version": "[^"]*"' | cut -d'"' -f4)

# A tag you created in ../boboko-core but never pushed won't be resolved.
if [ -d ../boboko-core ]; then
    latest=$(git -C ../boboko-core tag --sort=-v:refname | head -1)
    if [ -n "$latest" ] && [ "$latest" != "v$version" ]; then
        echo "!!! Warning: resolved boboko/core $version, but ../boboko-core's newest tag is $latest."
        echo "!!!          Did you push it? (git -C ../boboko-core push origin $latest)"
    fi
fi

if ! git diff --quiet HEAD -- composer.lock package-lock.json; then
    echo ">>> Committing lockfiles for boboko/core $version..."
    git add composer.lock package-lock.json
    git commit -m "Chore: Bumping boboko/core to $version"
fi

echo
echo ">>> Deploying $branch to $host with boboko/core $version."
pending=$(git log --oneline "origin/$branch..HEAD")
if [ -n "$pending" ]; then
    echo ">>> Commits to push:"
    echo "$pending"
else
    echo ">>> Nothing new to push — this redeploys origin/$branch as-is."
fi
echo
read -r -p "Push and deploy? [y/N] " answer
[ "$answer" = y ] || [ "$answer" = Y ] || fail "Aborted."

if [ -n "$pending" ]; then
    git push origin "$branch"
fi

vendor/bin/envoy run deploy

echo
echo ">>> Done. You're in repo mode — run bin/core-mode local to go back to your ../boboko-core checkout."
