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

tmp_dir="$(mktemp -d)"
cleanup() {
  rm -rf "$tmp_dir"
}
trap cleanup EXIT

installer="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/install-workflow"
package_json="$(dirname "$installer")/../package.json"

json_value() {
  local file="$1"
  local expression="$2"

  node - "$file" "$expression" <<'NODE'
const fs = require("fs");
const file = process.argv[2];
const expression = process.argv[3];
const data = JSON.parse(fs.readFileSync(file, "utf8"));
const fn = new Function("data", `"use strict"; return (${expression});`);
const value = fn(data);
if (typeof value === "boolean") {
  console.log(value ? "true" : "false");
} else if (value === null || value === undefined) {
  console.log("");
} else {
  console.log(String(value));
}
NODE
}

git -C "$tmp_dir" init --quiet
"$installer" --target "$tmp_dir"

symlink_bin="${tmp_dir}/node_modules/.bin"
mkdir -p "$symlink_bin"
ln -s "$installer" "${symlink_bin}/agentrail"
symlink_target="${tmp_dir}/symlink-install"
"${symlink_bin}/agentrail" --target "$symlink_target"

if [[ ! -e "${symlink_target}/AGENTS.md" ]]; then
  echo "installer did not work through a package bin symlink" >&2
  exit 1
fi

if "$installer" --target --force >"${tmp_dir}/missing-target.out" 2>&1; then
  echo "--target accepted another option as its directory argument" >&2
  exit 1
fi

if ! grep -q -- "--target requires a directory" "${tmp_dir}/missing-target.out"; then
  echo "--target missing-argument error was not reported" >&2
  exit 1
fi

required=(
  "AGENTS.md"
  "CONTEXT.md"
  "docs/agents/issue-tracker.md"
  "docs/agents/agentrail-state.md"
  "docs/agents/github-pr-reviewer.md"
  "docs/agents/context-engine.md"
  "docs/agents/context-compiler-contract.md"
  "docs/agents/milestones.md"
  "docs/agents/ralph-loop.md"
  "docs/agents/pr-review.md"
  "docs/agents/skill-registry.json"
  "docs/agents/visual-evidence.md"
  "docs/agents/triage-labels.md"
  "docs/prd/.gitkeep"
  "docs/milestones/.gitkeep"
  "skills/backend-api/SKILL.md"
  "skills/desktop-tauri/SKILL.md"
  "skills/devops-deploy/SKILL.md"
  "skills/docs-current/SKILL.md"
  "skills/frontend-web/SKILL.md"
  "skills/bensigo-ai-workflow/SKILL.md"
  "skills/grill-with-docs/SKILL.md"
  "skills/grill-with-docs/ADR-FORMAT.md"
  "skills/grill-with-docs/CONTEXT-FORMAT.md"
  "skills/to-prd/SKILL.md"
  "skills/to-milestones/SKILL.md"
  "skills/to-milestones/agents/openai.yaml"
  "skills/to-issues/SKILL.md"
  "skills/tdd/SKILL.md"
  "skills/tdd/deep-modules.md"
  "skills/tdd/interface-design.md"
  "skills/tdd/mocking.md"
  "skills/tdd/refactoring.md"
  "skills/tdd/tests.md"
  ".agentrail/state.json"
  ".agentrail/config.json"
  "scripts/agentrail"
  ".agentrail/source/scripts/agentrail"
  ".agentrail/source/scripts/agentrail-legacy"
  ".agentrail/source/scripts/install-workflow"
  ".agentrail/source/agentrail/__init__.py"
  ".agentrail/source/agentrail/context/sources.py"
  ".agentrail/source/agentrail/context/index.py"
  ".agentrail/source/agentrail/context/redaction.py"
  ".agentrail/source/agentrail/context/embeddings.py"
  ".agentrail/source/agentrail/context/packs.py"
  ".agentrail/source/agentrail/context/retrieval.py"
  ".agentrail/source/templates/scripts/memory"
  ".agentrail/source/templates/scripts/afk-workflow"
  ".agentrail/source/templates/scripts/pr"
  ".agentrail/source/templates/scripts/ralph-loop"
  ".agentrail/source/templates/scripts/review-pr"
)

for file in "${required[@]}"; do
  if [[ ! -e "${tmp_dir}/${file}" ]]; then
    echo "missing installed file: ${file}" >&2
    exit 1
  fi
done

for script in memory ralph-loop afk-workflow review-pr pr; do
  if [[ -e "${tmp_dir}/scripts/${script}" ]]; then
    echo "raw workflow script was installed into normal project surface: scripts/${script}" >&2
    exit 1
  fi
  if [[ ! -x "${tmp_dir}/.agentrail/source/templates/scripts/${script}" ]]; then
    echo "hidden internal script is not executable: .agentrail/source/templates/scripts/${script}" >&2
    exit 1
  fi
done

sed '$d' "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow" >"${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow-lib"
# shellcheck disable=SC1090
source "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow-lib"
hidden_scripts_dir="$(cd -P "${tmp_dir}/.agentrail/source/templates/scripts" && pwd)"
if [[ "$(script_path "$tmp_dir" pr)" != "${hidden_scripts_dir}/pr" ]]; then
  echo "afk-workflow did not resolve adjacent internal pr helper" >&2
  exit 1
fi
if grep -q -- 'script_path "$root" "review-pr"' "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow"; then
  echo "afk-workflow still resolves the internal review-pr helper directly" >&2
  exit 1
fi
if ! grep -q -- "internal review-pr" "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow"; then
  echo "afk-workflow does not route reviews through the AgentRail CLI" >&2
  exit 1
fi

if [[ ! -x "${tmp_dir}/scripts/agentrail" ]]; then
  echo "agentrail CLI shim was not installed into normal project surface" >&2
  exit 1
fi

"${tmp_dir}/scripts/agentrail" upgrade --target "$tmp_dir" >"${tmp_dir}/installed-agentrail-upgrade.out"
if ! grep -q -- "AgentRail upgrade:" "${tmp_dir}/installed-agentrail-upgrade.out"; then
  echo "installed agentrail CLI could not run upgrade" >&2
  cat "${tmp_dir}/installed-agentrail-upgrade.out" >&2
  exit 1
fi

for skill in grill-with-docs to-prd to-milestones to-issues tdd; do
  if ! grep -q -- "$skill" "${tmp_dir}/AGENTS.md"; then
    echo "AGENTS.md does not mention required skill: ${skill}" >&2
    exit 1
  fi
done

if ! grep -q -- "Acceptance Criteria Coverage" "${tmp_dir}/docs/agents/ralph-loop.md"; then
  echo "ralph-loop docs do not require acceptance criteria coverage" >&2
  exit 1
fi

if ! grep -q -- "memory_suggestions" "${tmp_dir}/docs/agents/github-pr-reviewer.md"; then
  echo "github-pr-reviewer docs do not describe memory suggestions" >&2
  exit 1
fi

if ! grep -q -- ".agentrail/state.json" "${tmp_dir}/docs/agents/agentrail-state.md"; then
  echo "agentrail state docs do not describe the state file path" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "data.agentrailVersion")" != "$(json_value "$package_json" "data.version")" ]]; then
  echo "state file does not record the AgentRail version" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "data.managedFiles.find((file) => file.path === 'AGENTS.md')?.contentHash")" != sha256:* ]]; then
  echo "state file does not record content hashes for managed files" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "['phase', 'activeIssue', 'activePullRequest', 'activePrd', 'activeMilestone', 'activeRun', 'completedRuns', 'goals', 'lastCompletedStep', 'nextSuggestedAction'].every((field) => Object.prototype.hasOwnProperty.call(data.workflow, field))")" != "true" ]]; then
  echo "state file does not include resumable workflow fields" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "data.legacyAdopted")" != "false" ]]; then
  echo "fresh install was incorrectly marked as legacy-adopted" >&2
  exit 1
fi

if ! grep -q -- "Acceptance Criteria Coverage" "${tmp_dir}/docs/agents/pr-review.md"; then
  echo "pr-review docs do not require acceptance criteria coverage checks" >&2
  exit 1
fi

if ! grep -q -- "docs/agents/pr-review.md" "${tmp_dir}/.agentrail/source/templates/scripts/review-pr"; then
  echo "review-pr script does not load installed PR review instructions" >&2
  exit 1
fi

if ! grep -q -- "docs/agents/github-pr-reviewer.md" "${tmp_dir}/.agentrail/source/templates/scripts/review-pr"; then
  echo "review-pr script does not load installed GitHub PR reviewer contract" >&2
  exit 1
fi

if ! grep -q -- "--machine-readable" "${tmp_dir}/.agentrail/source/templates/scripts/review-pr"; then
  echo "internal review helper does not support machine-readable review mode" >&2
  exit 1
fi

if ! grep -q -- "internal review-pr --pr" "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow"; then
  echo "afk-workflow does not request PR reviews through the AgentRail CLI" >&2
  exit 1
fi

if ! grep -q -- "--machine-readable" "${tmp_dir}/.agentrail/source/templates/scripts/afk-workflow"; then
  echo "afk-workflow does not request machine-readable PR reviews through the AgentRail CLI" >&2
  exit 1
fi

if grep -q -- "review/prompt.md" "${tmp_dir}/.agentrail/source/templates/scripts/review-pr"; then
  echo "review-pr script still depends on missing review/prompt.md" >&2
  exit 1
fi

if ! grep -q -- "AC1" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill does not require labeled acceptance criteria" >&2
  exit 1
fi

if ! grep -q -- "CONTEXT.md.*mandatory" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill does not require mandatory CONTEXT.md ingestion" >&2
  exit 1
fi

if ! grep -q -- "TASTE.md.*when present" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill does not require TASTE.md ingestion when present" >&2
  exit 1
fi

if ! grep -q -- "## Required context" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill issue template does not carry required context into issues" >&2
  exit 1
fi

if ! grep -q -- "## Verification evidence" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill does not separate verification evidence from acceptance criteria" >&2
  exit 1
fi

if grep -q -- "AC3: <Required verification evidence" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill still models verification evidence as an acceptance criterion" >&2
  exit 1
fi

if ! grep -q -- "CONTEXT.md.*mandatory" "${tmp_dir}/skills/to-milestones/SKILL.md"; then
  echo "to-milestones skill does not require mandatory CONTEXT.md ingestion" >&2
  exit 1
fi

if ! grep -q -- "TASTE.md.*when present" "${tmp_dir}/skills/to-milestones/SKILL.md"; then
  echo "to-milestones skill does not require TASTE.md ingestion when present" >&2
  exit 1
fi

if ! grep -q -- "## Required Context" "${tmp_dir}/skills/to-milestones/SKILL.md"; then
  echo "to-milestones skill template does not record required context" >&2
  exit 1
fi

if ! grep -q -- "docs/milestones/001-" "${tmp_dir}/skills/to-milestones/SKILL.md"; then
  echo "to-milestones skill does not use docs/milestones path convention" >&2
  exit 1
fi

if ! grep -q -- "docs/milestones/NNN-slug.md" "${tmp_dir}/skills/to-issues/SKILL.md"; then
  echo "to-issues skill does not use docs/milestones path convention" >&2
  exit 1
fi

if ! grep -q -- "agentrail memory recall" "${tmp_dir}/AGENTS.md"; then
  echo "AGENTS.md does not tell agents to recall project memory" >&2
  exit 1
fi

if ! grep -q -- "agentrail memory recall" "${tmp_dir}/docs/agents/ralph-loop.md"; then
  echo "ralph-loop docs do not require project memory recall" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "data.managedFiles.some((file) => file.path === 'docs/agents/skill-registry.json' && file.source === 'templates/docs/agents/skill-registry.json')")" != "true" ]]; then
  echo "state file does not track the managed skill registry" >&2
  exit 1
fi

if [[ "$(json_value "${tmp_dir}/.agentrail/state.json" "data.managedFiles.some((file) => file.path === 'skills/frontend-web/SKILL.md' && file.source === 'skills/frontend-web/SKILL.md')")" != "true" ]]; then
  echo "state file does not track bundled skill files" >&2
  exit 1
fi

if [[ -f "${tmp_dir}/TASTE.md" ]]; then
  echo "TASTE.md should not be installed (created lazily during grill)" >&2
  exit 1
fi

for excluded_file in ".claude/agents/github-pr-reviewer.md" ".codex/agents/github-pr-reviewer.md" "docs/memory/README.md" "docs/prd/context-engine.md"; do
  if [[ -f "${tmp_dir}/${excluded_file}" ]]; then
    echo "${excluded_file} should not be installed by init" >&2
    exit 1
  fi
done

if ! grep -q -- "TASTE.md" "${tmp_dir}/AGENTS.md"; then
  echo "AGENTS.md does not tell agents to read TASTE.md when present" >&2
  exit 1
fi

if ! grep -q -- "borrow aggressively, vendor carefully, update intentionally, never auto-trust" "${tmp_dir}/AGENTS.md"; then
  echo "AGENTS.md does not document the skill supply-chain rule" >&2
  exit 1
fi

if ! grep -q -- "verify the upstream source still exists before editing docs/agents/skill-registry.json" "${tmp_dir}/AGENTS.md"; then
  echo "AGENTS.md does not document safe provenance update expectations" >&2
  exit 1
fi

(
  cd "$tmp_dir"
  mkdir -p docs/memory
  cat > docs/memory/decisions.md <<'MEMORY'
# Decisions
MEMORY
  cat >> docs/memory/decisions.md <<'MEMORY'

## Prefer server-side validation

- kind: decision
- source: docs/adr/0001-validation.md
- confidence: verified

Keep validation rules server-side when they affect persisted business state.
MEMORY

  if ! "${tmp_dir}/scripts/agentrail" memory recall "validation" | grep -q -- "Prefer server-side validation"; then
    echo "memory recall did not find relevant installed memory" >&2
    exit 1
  fi

  if ! "${tmp_dir}/scripts/agentrail" memory recall "persisted validation" | grep -q -- "Prefer server-side validation"; then
    echo "memory recall did not handle multiple non-adjacent query terms" >&2
    exit 1
  fi

  cat > docs/memory/lessons.md <<'MEMORY'
# Lessons
MEMORY
  cat >> docs/memory/lessons.md <<'MEMORY'

## [codex] Bracketed PR titles stay literal

- kind: lesson
- source: PR #4
- confidence: verified

Recall queries should treat bracketed PR title prefixes as literal text.
MEMORY

  no_rg_bin="${tmp_dir}/no-rg-bin"
  mkdir -p "$no_rg_bin"
  for binary in bash dirname git grep node pwd readlink; do
    ln -s "$(command -v "$binary")" "${no_rg_bin}/${binary}"
  done

  PATH="$no_rg_bin" "${tmp_dir}/scripts/agentrail" memory recall "[codex]" > "${tmp_dir}/bracketed-recall.out"

  if ! grep -q -- "Bracketed PR titles stay literal" "${tmp_dir}/bracketed-recall.out"; then
    echo "memory recall grep fallback did not find a bracketed literal query" >&2
    exit 1
  fi

  if grep -q -- "# Project Memory" "${tmp_dir}/bracketed-recall.out"; then
    echo "memory recall grep fallback treated bracketed query as a regex" >&2
    exit 1
  fi
)

legacy_dir="$(mktemp -d "${tmp_dir}/legacy.XXXXXX")"
git -C "$legacy_dir" init --quiet
mkdir -p "${legacy_dir}/docs/agents"
cat > "${legacy_dir}/AGENTS.md" <<'LEGACY'
# Local agent instructions

Do not delete this local edit.
LEGACY
cat > "${legacy_dir}/docs/agents/ralph-loop.md" <<'LEGACY'
# Local Ralph Loop

Keep this local workflow edit.
LEGACY

"$installer" --target "$legacy_dir" >"${tmp_dir}/legacy-install.out"

if [[ ! -e "${legacy_dir}/.agentrail/state.json" ]]; then
  echo "legacy adoption did not create .agentrail/state.json" >&2
  exit 1
fi

if ! grep -q -- "Do not delete this local edit." "${legacy_dir}/AGENTS.md"; then
  echo "legacy adoption deleted local AGENTS.md edits" >&2
  exit 1
fi

if ! grep -q -- "Keep this local workflow edit." "${legacy_dir}/docs/agents/ralph-loop.md"; then
  echo "legacy adoption deleted local ralph-loop edits" >&2
  exit 1
fi

if [[ "$(json_value "${legacy_dir}/.agentrail/state.json" "data.legacyAdopted")" != "true" ]]; then
  echo "legacy install without prior state was not marked as adopted" >&2
  exit 1
fi

if [[ "$(json_value "${legacy_dir}/.agentrail/state.json" "data.managedFiles.find((file) => file.path === 'AGENTS.md')?.installStatus")" != "legacy-adopted" ]]; then
  echo "legacy AGENTS.md was not recorded as adopted" >&2
  exit 1
fi

echo "install test passed"
