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

ACTION="${1:-setup}"
LAB_ROOT="${2:-/tmp/soria-git-github-${USER:-student}}"
MARKER_NAME=".soria-git-github-collaboration"

fail() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

resolve_safe_root() {
  case "$LAB_ROOT" in
    /tmp/soria-git-*|"${HOME}"/soria-git-*) ;;
    *) fail "refused lab root: $LAB_ROOT" ;;
  esac
  [ "$LAB_ROOT" != "/tmp" ] || fail "refused root: /tmp"
  [ "$LAB_ROOT" != "$HOME" ] || fail "refused root: $HOME"
}

require_marker() {
  [ -f "$LAB_ROOT/$MARKER_NAME" ] || fail "missing marker: $LAB_ROOT/$MARKER_NAME"
}

configure_repo() {
  local repo="$1"
  local identity="$2"
  git -C "$repo" config user.name "$identity"
  git -C "$repo" config user.email "${identity,,}@soria.invalid"
  git -C "$repo" config init.defaultBranch main
  git -C "$repo" config pull.ff only
  git -C "$repo" config fetch.prune true
}

commit_path() {
  local repo="$1"
  local path="$2"
  local message="$3"
  git -C "$repo" add "$path"
  git -C "$repo" commit -q -m "$message"
}

setup_lab() {
  if [ -e "$LAB_ROOT" ]; then
    require_marker
    rm -rf "$LAB_ROOT/origin.git" "$LAB_ROOT/seed" "$LAB_ROOT/alice" \
      "$LAB_ROOT/bob" "$LAB_ROOT/maintainer" "$LAB_ROOT/evidence"
  else
    mkdir -p "$LAB_ROOT"
    : > "$LAB_ROOT/$MARKER_NAME"
  fi

  mkdir -p "$LAB_ROOT/evidence"
  git init -q --bare --initial-branch=main "$LAB_ROOT/origin.git"

  git init -q -b main "$LAB_ROOT/seed"
  configure_repo "$LAB_ROOT/seed" "Seed"
  cat > "$LAB_ROOT/seed/README.md" <<'TXT'
# SORIA Infrastructure Repository

Changes are integrated through reviewed branches.
TXT
  cat > "$LAB_ROOT/seed/platform.conf" <<'TXT'
environment=staging
backup_check=disabled
TXT
  cat > "$LAB_ROOT/seed/.gitignore" <<'TXT'
.env
*.log
artifacts/
TXT
  commit_path "$LAB_ROOT/seed" . "chore: initialize infrastructure repository"
  git -C "$LAB_ROOT/seed" remote add origin "$LAB_ROOT/origin.git"
  git -C "$LAB_ROOT/seed" push -q -u origin main
  git -C "$LAB_ROOT/origin.git" symbolic-ref HEAD refs/heads/main

  git clone -q "$LAB_ROOT/origin.git" "$LAB_ROOT/alice"
  git clone -q "$LAB_ROOT/origin.git" "$LAB_ROOT/bob"
  git clone -q "$LAB_ROOT/origin.git" "$LAB_ROOT/maintainer"
  configure_repo "$LAB_ROOT/alice" "Alice"
  configure_repo "$LAB_ROOT/bob" "Bob"
  configure_repo "$LAB_ROOT/maintainer" "Maintainer"

  cat > "$LAB_ROOT/evidence/authentication-checklist.md" <<'TXT'
# Authentication checklist

- Prefer SSH keys, Git Credential Manager or `gh auth login`.
- Never place a token in a remote URL, shell history, tracked file or commit message.
- Inspect `git remote -v` before sharing terminal output.
- Use the minimum permissions required and rotate a credential after suspected exposure.
TXT

  cat > "$LAB_ROOT/evidence/pull-request-template.md" <<'TXT'
## Why
Explain the operational problem.

## What changed
Describe the smallest reviewable change.

## Validation
- [ ] Diff reviewed locally
- [ ] Automated checks pass
- [ ] No secret or generated artifact is committed
- [ ] Rollback is documented

## Evidence
Attach commands, logs or screenshots without credentials.
TXT

  cat > "$LAB_ROOT/evidence/review-checklist.md" <<'TXT'
# Review checklist

- Correctness and scope
- Security and secret hygiene
- Failure modes and rollback
- Tests and reproducibility
- Documentation and maintainability
TXT

  cat > "$LAB_ROOT/evidence/issue.md" <<'TXT'
# Issue: enable the backup health check

## Problem
The staging configuration does not expose backup verification.

## Acceptance criteria
- `backup_check=enabled` is present.
- A runbook explains validation and rollback.
- The change is merged through a reviewed branch.
TXT

  cat > "$LAB_ROOT/evidence/branch-rules.json" <<'JSON'
{
  "target": "main",
  "require_pull_request": true,
  "required_approvals": 1,
  "dismiss_stale_approvals": true,
  "require_status_checks": true,
  "block_force_push": true,
  "block_deletion": true
}
JSON

  cat > "$LAB_ROOT/README.txt" <<'TXT'
Commands:
  setup     create one bare remote and three isolated collaborator clones
  status    inspect remotes, upstreams, branches and graph without changing them
  run       publish, review, amend and merge a feature through the local remote
  validate  verify collaboration state, evidence and credential hygiene
  reset     delete this marked lab directory

The bare repository simulates network collaboration without contacting GitHub.
GitHub pull requests, reviews, issues and rulesets are documented as evidence,
not falsely claimed as executed by this offline lab.
TXT

  printf 'GitHub collaboration laboratory ready: %s\n' "$LAB_ROOT"
}

show_status() {
  require_marker
  local name repo
  for name in alice bob maintainer; do
    repo="$LAB_ROOT/$name"
    printf '\n[%s]\n' "$name"
    git -C "$repo" remote -v
    git -C "$repo" status --short --branch
    git -C "$repo" branch -vv
    git -C "$repo" log --oneline --decorate --graph --all -10
  done
  printf '\n[origin refs]\n'
  git --git-dir="$LAB_ROOT/origin.git" for-each-ref \
    --format='%(refname:short) %(objectname:short)' refs/heads
}

run_reference() {
  require_marker
  local alice="$LAB_ROOT/alice"
  local bob="$LAB_ROOT/bob"
  local maintainer="$LAB_ROOT/maintainer"

  git -C "$alice" switch -q -c feature/backup-healthcheck
  cat > "$alice/platform.conf" <<'TXT'
environment=staging
backup_check=enabled
TXT
  mkdir -p "$alice/docs"
  cat > "$alice/docs/backup-validation.md" <<'TXT'
# Backup validation

1. Run the backup health check.
2. Record the timestamp and result.
3. Restore `backup_check=disabled` to roll back.
TXT
  commit_path "$alice" platform.conf "feat: enable backup health check"
  commit_path "$alice" docs/backup-validation.md "docs: add backup validation runbook"
  git -C "$alice" push -q -u origin feature/backup-healthcheck

  git -C "$bob" fetch -q origin
  git -C "$bob" switch -q --track -c review/backup-healthcheck \
    origin/feature/backup-healthcheck
  {
    printf 'base=origin/main\n'
    printf 'head=origin/feature/backup-healthcheck\n'
    git -C "$bob" diff --stat origin/main...origin/feature/backup-healthcheck
    printf 'review=request-changes\n'
    printf 'comment=Document the validation command and expected output.\n'
  } > "$LAB_ROOT/evidence/review-result.txt"

  cat >> "$alice/docs/backup-validation.md" <<'TXT'

Expected evidence:

```text
backup_check=enabled
result=healthy
```
TXT
  commit_path "$alice" docs/backup-validation.md \
    "docs: address backup validation review"
  git -C "$alice" push -q

  git -C "$bob" fetch -q origin
  {
    printf 'review=approve\n'
    printf 'reviewed_head=%s\n' \
      "$(git -C "$bob" rev-parse origin/feature/backup-healthcheck)"
    printf 'comment=Validation evidence and rollback are now explicit.\n'
  } > "$LAB_ROOT/evidence/review-approval.txt"

  git -C "$maintainer" fetch -q origin
  git -C "$maintainer" switch -q main
  git -C "$maintainer" merge --no-ff \
    origin/feature/backup-healthcheck \
    -m "merge: integrate backup health check" >/dev/null
  git -C "$maintainer" push -q origin main

  git -C "$alice" switch -q main
  git -C "$alice" pull -q --ff-only origin main
  git -C "$bob" switch -q main
  git -C "$bob" pull -q --ff-only origin main

  git -C "$maintainer" log --oneline --decorate --graph --all \
    > "$LAB_ROOT/evidence/final-graph.txt"
  git -C "$maintainer" show --stat --oneline HEAD \
    > "$LAB_ROOT/evidence/merge-summary.txt"

  printf 'Reference remote collaboration scenario completed.\n'
}

validate_reference() {
  require_marker
  local alice="$LAB_ROOT/alice"
  local bob="$LAB_ROOT/bob"
  local maintainer="$LAB_ROOT/maintainer"
  local origin="$LAB_ROOT/origin.git"
  local main_sha feature_sha parent_count

  main_sha="$(git --git-dir="$origin" rev-parse refs/heads/main)"
  feature_sha="$(git --git-dir="$origin" rev-parse refs/heads/feature/backup-healthcheck)"

  git --git-dir="$origin" merge-base --is-ancestor "$feature_sha" "$main_sha" \
    || fail "main does not contain the reviewed feature"
  parent_count="$(git --git-dir="$origin" show -s --format='%P' "$main_sha" | awk '{print NF}')"
  [ "$parent_count" -eq 2 ] || fail "main should end with a two-parent merge commit"

  for repo in "$alice" "$bob" "$maintainer"; do
    [ -z "$(git -C "$repo" status --porcelain)" ] || fail "repository is not clean: $repo"
    [ "$(git -C "$repo" rev-parse main)" = "$main_sha" ] || fail "main is stale: $repo"
    [ "$(git -C "$repo" remote get-url origin)" = "$origin" ] \
      || fail "unexpected origin URL: $repo"
    ! git -C "$repo" remote -v | grep -Eiq '(token|password|oauth|ghp_|github_pat_)' \
      || fail "credential-like data found in remote configuration: $repo"
  done

  [ "$(git -C "$alice" rev-parse --abbrev-ref feature/backup-healthcheck@{upstream})" = \
    'origin/feature/backup-healthcheck' ] || fail "feature upstream is not configured"

  grep -Fxq 'backup_check=enabled' "$maintainer/platform.conf" \
    || fail "merged configuration is missing"
  grep -Fq 'Expected evidence:' "$maintainer/docs/backup-validation.md" \
    || fail "review correction is missing"
  grep -Fxq 'review=request-changes' "$LAB_ROOT/evidence/review-result.txt" \
    || fail "request-changes evidence is missing"
  grep -Fxq 'review=approve' "$LAB_ROOT/evidence/review-approval.txt" \
    || fail "approval evidence is missing"

  for file in authentication-checklist.md pull-request-template.md \
    review-checklist.md issue.md branch-rules.json final-graph.txt merge-summary.txt; do
    [ -s "$LAB_ROOT/evidence/$file" ] || fail "missing evidence: $file"
  done

  grep -Fq '"require_pull_request": true' "$LAB_ROOT/evidence/branch-rules.json" \
    || fail "pull request rule is missing"
  grep -Fq '"require_status_checks": true' "$LAB_ROOT/evidence/branch-rules.json" \
    || fail "status-check rule is missing"
  grep -Fq '"block_force_push": true' "$LAB_ROOT/evidence/branch-rules.json" \
    || fail "force-push protection is missing"

  ! git --git-dir="$origin" grep -I -E \
    '(ghp_[[:alnum:]_]+|github_pat_[[:alnum:]_]+|password[[:space:]]*=|token[[:space:]]*=)' \
    "$main_sha" -- . >/dev/null 2>&1 \
    || fail "credential-like data found in main history"

  printf 'Validation successful: remote flow, upstream, review evidence, merge policy and credential hygiene are correct.\n'
}

reset_lab() {
  require_marker
  rm -rf "$LAB_ROOT"
  printf 'GitHub collaboration laboratory removed: %s\n' "$LAB_ROOT"
}

resolve_safe_root

case "$ACTION" in
  setup) setup_lab ;;
  status) show_status ;;
  run) run_reference ;;
  validate) validate_reference ;;
  reset) reset_lab ;;
  *) fail "unknown action: $ACTION (expected setup|status|run|validate|reset)" ;;
esac
