#!/usr/bin/env bash

set -euo pipefail

SOURCE_PATH="${BASH_SOURCE[0]}"
while [[ -L "$SOURCE_PATH" ]]; do
  SOURCE_DIR="$(cd -P "$(dirname "$SOURCE_PATH")" && pwd)"
  SOURCE_PATH="$(readlink "$SOURCE_PATH")"
  [[ "$SOURCE_PATH" != /* ]] && SOURCE_PATH="$SOURCE_DIR/$SOURCE_PATH"
done

SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE_PATH")" && pwd)"
WORKSPACE_ROOT="$(cd -P "$SCRIPT_DIR/.." && pwd)"
PROJECT_ID="okstra-validation"

# shellcheck source=lib/common.sh
source "$SCRIPT_DIR/lib/common.sh"
# shellcheck source=lib/paths.sh
source "$SCRIPT_DIR/lib/paths.sh"

PROJECT_ROOT="$(resolve_validation_project_root)"
export OKSTRA_HOME="${OKSTRA_HOME:-$PROJECT_ROOT/.okstra-home}"

WORKSPACE_APP_PATH="$PROJECT_ROOT"
OKSTRA_SCRIPT="$WORKSPACE_ROOT/scripts/okstra.sh"
RUN_VALIDATOR_PATH="$WORKSPACE_ROOT/validators/validate-run.py"
SOURCE_ASSET_ROOT="$WORKSPACE_ROOT/agents"
# Arbitrary sample task-type used only to exercise the bundle-prep /
# discovery-pointer / task-catalog / asset-seeding machinery via render-only
# run_okstra. Must NOT require --approved-plan (excludes implementation and
# final-verification) and must have a tests/fixtures/final-report-data/
# <task-type>-001.data.json sample (used by prepare_run_validator_fixture).
TASK_TYPE="requirements-discovery"
PRIMARY_TASK_GROUP="validation"
PRIMARY_TASK_ID="asset-refresh-and-reference-expectations"
PRIMARY_BRIEF_FILENAME="validation-brief-primary.md"
SECONDARY_TASK_GROUP="discovery"
SECONDARY_TASK_ID="task-catalog"
SECONDARY_BRIEF_FILENAME="validation-brief-secondary.md"

# Workflow validation is a hermetic contract test for bundle prep / discovery
# artifacts / validator round-trips. It must not depend on the developer or CI
# machine having a preinstalled ~/.okstra runtime. The synthetic prepare below
# reconciles the run index (okstra_ctl.run._reconcile_prior_runs); it stays off
# unrelated local state because OKSTRA_HOME is redirected above and the
# reconcile is scoped to this fixture's project id.
export OKSTRA_SKIP_INSTALL_CHECK="${OKSTRA_SKIP_INSTALL_CHECK:-1}"
# Same reason as the one above: the synthetic run must render the same way on
# every machine. A maintainer running this from inside cmux would otherwise get
# the cmux adapter and a lead-session requirement this fixture never simulates. The cmux path has its own coverage
# in tests/run/test_cmux*.py and tests/contract/test_validate_session_conformance.py.
export CMUX_WORKSPACE_ID=""

LATEST_TASK_RELATIVE_PATH="$OKSTRA_DIR/discovery/latest-task.json"
TASK_CATALOG_RELATIVE_PATH="$OKSTRA_DIR/discovery/task-catalog.json"
# shellcheck source=lib/fixtures.sh
source "$SCRIPT_DIR/lib/fixtures.sh"
# shellcheck source=lib/runners.sh
source "$SCRIPT_DIR/lib/runners.sh"
# shellcheck source=lib/validate-assets.sh
source "$SCRIPT_DIR/lib/validate-assets.sh"
# shellcheck source=lib/validate-prompt-metadata.sh
source "$SCRIPT_DIR/lib/validate-prompt-metadata.sh"
# shellcheck source=lib/validate-tasks.sh
source "$SCRIPT_DIR/lib/validate-tasks.sh"
# shellcheck source=lib/summary.sh
source "$SCRIPT_DIR/lib/summary.sh"

trap 'on_error "$LINENO"' ERR

# 기본(mktemp) 루트는 이 실행이 소유한다: 성공 시 제거, 실패 시 진단을 위해
# 보존. OKSTRA_VALIDATION_PROJECT_ROOT 가 지정된 루트의 수명은 호출자 소유.
cleanup_validation_root() {
  local exit_code=$?

  if [[ -n "${OKSTRA_VALIDATION_PROJECT_ROOT:-}" ]]; then
    return
  fi

  if [[ "$exit_code" -eq 0 ]]; then
    rm -rf "$PROJECT_ROOT"
  else
    printf '[INFO] Validation root retained for inspection: %s\n' "$PROJECT_ROOT" >&2
  fi
}
trap cleanup_validation_root EXIT

require_file "$OKSTRA_SCRIPT"
require_file "$RUN_VALIDATOR_PATH"

validate_project_root_safety

PRIMARY_BRIEF_PATH="$PROJECT_ROOT/$PRIMARY_BRIEF_FILENAME"
SECONDARY_BRIEF_PATH="$PROJECT_ROOT/$SECONDARY_BRIEF_FILENAME"
DISCOVERY_FILE="$PROJECT_ROOT/$LATEST_TASK_RELATIVE_PATH"
CATALOG_FILE="$PROJECT_ROOT/$TASK_CATALOG_RELATIVE_PATH"
PRIMARY_TASK_KEY="$(task_key "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID")"
SECONDARY_TASK_KEY="$(task_key "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID")"
PRIMARY_REFERENCE_EXPECTATIONS_FILE="$(task_root "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID")/instruction-set/reference-expectations.md"
SECONDARY_REFERENCE_EXPECTATIONS_FILE="$(task_root "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID")/instruction-set/reference-expectations.md"

step "Resetting the validation root"
reset_validation_root
pass "Validation root reset: $PROJECT_ROOT"

step "Writing validation briefs for multiple tasks"
write_validation_brief \
  "$PRIMARY_BRIEF_PATH" \
  "Primary validation brief for reference expectations" \
  "$PRIMARY_TASK_GROUP" \
  "$PRIMARY_TASK_ID" \
  "verify the initial task bundle and discovery pointer"
write_validation_brief \
  "$SECONDARY_BRIEF_PATH" \
  "Secondary validation brief for discovery catalog" \
  "$SECONDARY_TASK_GROUP" \
  "$SECONDARY_TASK_ID" \
  "verify task catalog retention across multiple prepared tasks"
require_file "$PRIMARY_BRIEF_PATH"
require_file "$SECONDARY_BRIEF_PATH"
pass "Validation briefs created for primary and secondary tasks"

step "Running the initial render-only okstra validation for the primary task"
if ! run_okstra "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" "$PRIMARY_BRIEF_FILENAME"; then
  fail "Initial okstra render-only validation for the primary task failed"
fi
pass "Primary task render-only validation completed"

step "Checking seeded assets and primary task discovery artifacts"
if ! validate_seeded_assets match; then
  fail "Seeded project-local okstra assets are missing or do not match the source files"
fi
if ! validate_reference_expectations "$PRIMARY_BRIEF_PATH" "$PRIMARY_REFERENCE_EXPECTATIONS_FILE" "$PRIMARY_TASK_KEY"; then
  fail "Primary reference-expectations.md does not preserve the expected brief content"
fi
if ! validate_task_artifacts "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID"; then
  fail "Primary task manifest or run manifest validation failed"
fi
if ! validate_worker_prompt_metadata "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID"; then
  fail "Primary worker prompt metadata validation failed"
fi
if ! validate_latest_task_pointer "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID"; then
  fail "latest-task.json did not point to the primary task after the first run"
fi
if ! validate_task_catalog "$PRIMARY_TASK_KEY" "$PRIMARY_TASK_KEY"; then
  fail "task-catalog.json did not preserve the expected primary task entry"
fi
pass "Primary task discovery artifacts are valid"

step "Preparing validator fixture artifacts for the primary task"
# Fixture needs to render Phase 7 step 1.5 sibling artifacts; pass the
# repo root so the heredoc can import okstra_ctl.report_views and load
# inline assets from templates/reports/.
export OKSTRA_WORKSPACE_ROOT_FOR_FIXTURE="$WORKSPACE_ROOT"
if ! prepare_run_validator_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex-analyser; then
  fail "Failed to prepare validator fixture artifacts for the primary task"
fi
pass "Primary task validator fixture prepared with an intentionally missing Codex prompt history file"

step "Ensuring the run validator rejects attempted workers without prompt history"
if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" failed "Codex analyser with status \`timeout\` is missing worker prompt history file"; then
  fail "Run validator did not reject the missing worker prompt history artifact"
fi
pass "Run validator rejected the missing worker prompt history artifact as expected"

step "Restoring the missing worker prompt history file and rerunning the validator"
if ! write_worker_prompt_history_fixture "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" codex-analyser; then
  fail "Failed to write the missing worker prompt history fixture"
fi
if ! run_validator_expectation "$PRIMARY_TASK_GROUP" "$PRIMARY_TASK_ID" passed; then
  fail "Run validator did not pass after restoring the worker prompt history artifact"
fi
pass "Run validator passed after the missing worker prompt history artifact was restored"

step "Checking that the validated run is settled in the central run index"
# The global index (~/.okstra) records a run's start via record_start and never
# its end; validate-run is what writes the end
# (record_validation_in_central_index). Without that edge the row stays
# `prepared`/`running` forever and run-audit reads it as a run that has not
# produced its report yet. This run was validated twice here — `failed`, then
# `passed` — so a passing row also proves the second verdict overwrote the first.
RECENT_INDEX="$OKSTRA_HOME/recent.jsonl"
require_file "$RECENT_INDEX"
PRIMARY_RUN_ID="$PROJECT_ID/$PRIMARY_TASK_GROUP/$PRIMARY_TASK_ID/$TASK_TYPE/r01"
PRIMARY_INDEX_ROW="$(grep -F "\"runId\":\"$PRIMARY_RUN_ID\"" "$RECENT_INDEX" || true)"
if [[ -z "$PRIMARY_INDEX_ROW" ]]; then
  fail "No central run-index row for $PRIMARY_RUN_ID"
fi
if ! printf '%s' "$PRIMARY_INDEX_ROW" | grep -qF '"status":"completed"'; then
  fail "Central run-index row for $PRIMARY_RUN_ID is not completed: $PRIMARY_INDEX_ROW"
fi
if ! printf '%s' "$PRIMARY_INDEX_ROW" | grep -qF '"validation":"passed"'; then
  fail "Central run-index row for $PRIMARY_RUN_ID does not carry the passing verdict: $PRIMARY_INDEX_ROW"
fi
pass "Central run-index row for the primary run reads completed/passed"

step "Running a second render-only okstra validation for the secondary task"
if ! run_okstra "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID" "$SECONDARY_BRIEF_FILENAME"; then
  fail "Render-only validation for the secondary task failed"
fi
pass "Secondary task render-only validation completed"

step "Checking that latest-task.json moves while task-catalog.json retains both tasks"
if ! validate_reference_expectations "$SECONDARY_BRIEF_PATH" "$SECONDARY_REFERENCE_EXPECTATIONS_FILE" "$SECONDARY_TASK_KEY"; then
  fail "Secondary reference-expectations.md does not preserve the expected brief content"
fi
if ! validate_task_artifacts "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID"; then
  fail "Secondary task manifest or run manifest validation failed"
fi
if ! validate_worker_prompt_metadata "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID"; then
  fail "Secondary worker prompt metadata validation failed"
fi
if ! validate_latest_task_pointer "$SECONDARY_TASK_GROUP" "$SECONDARY_TASK_ID"; then
  fail "latest-task.json did not point to the secondary task after the second run"
fi
if ! validate_task_catalog "$SECONDARY_TASK_KEY" "$PRIMARY_TASK_KEY" "$SECONDARY_TASK_KEY"; then
  fail "task-catalog.json did not preserve both prepared tasks"
fi
pass "latest-task.json and task-catalog.json now reflect distinct primary and secondary tasks"

# Removed: the historical "rerun without refresh preserves project-local
# assets" and "rerun with refresh regenerates project-local assets" stanzas.
# Those tested a contract from when `okstra install` seeded per-project
# `.claude/` files; install now writes only to `$HOME/.claude` and
# `$HOME/.okstra`, so the project-local sentinel is no longer a meaningful
# contract. The `--refresh-assets` flag was removed entirely in a paired
# commit; users with old scripts should switch to `okstra install --refresh`.

print_summary
