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

MODE="${1:-}"
ROOT="${2:-}"
SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FIXTURES="$SELF_DIR/fixtures/lot4"
MARKER=".soria-ir-containment-eradication-recovery"
SAFETY_MARKER="SIMULATION_ONLY_NO_LIVE_ACTIONS"
DECISION="RECOVERY_READY_WITH_ACTIONS"

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

safe_root(){
  case "$ROOT" in
    /tmp/soria-ir-*|"$HOME"/soria-ir-*) ;;
    *) fail "unsafe root: $ROOT" ;;
  esac
}

need_file(){ [[ -f "$1" ]] || fail "missing file: $1"; }
fixture_count(){ find "$1" -type f | wc -l | tr -d ' '; }

verify_manifest(){
  need_file "$ROOT/source-integrity.sha256"
  ( cd "$ROOT/source"; sha256sum -c "$ROOT/source-integrity.sha256" >/dev/null ) || fail "source fixture integrity mismatch"
}

known_asset(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id {found=1} END{exit(found?0:1)}' "$ROOT/source/context/assets.csv"; }
known_impact(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id && $3!="" && $4!="" {found=1} END{exit(found?0:1)}' "$ROOT/source/business/impact.csv"; }
known_exit(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id && $2!="" && $3!="" {found=1} END{exit(found?0:1)}' "$ROOT/source/eradication/exit-criteria.csv"; }
known_rollback(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id && $2!="" && $3!="" {found=1} END{exit(found?0:1)}' "$ROOT/source/change/rollback.csv"; }
trusted_source(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id && $5=="PASS" {found=1} END{exit(found?0:1)}' "$ROOT/source/recovery/trusted-state.csv"; }
known_reopen(){ local id="$1"; awk -F, -v id="$id" 'NR>1 && $1==id && $2!="" && $3=="REOPEN" {found=1} END{exit(found?0:1)}' "$ROOT/source/monitoring/reopen-criteria.csv"; }

setup(){
  safe_root
  [[ -d "$FIXTURES" ]] || fail "missing fixture bundle"
  [[ "$(fixture_count "$FIXTURES")" -eq 18 ]] || fail "expected exactly 18 Lot 4 fixtures"
  rm -rf -- "$ROOT"
  mkdir -p "$ROOT/source" "$ROOT/output" "$ROOT/work/negative"
  cp -R "$FIXTURES"/. "$ROOT/source/"
  printf '%s\n' "$SAFETY_MARKER" > "$ROOT/$MARKER"
  ( cd "$ROOT/source"; find . -type f -print | sort | while read -r f; do sha256sum "$f"; done ) > "$ROOT/source-integrity.sha256"
  verify_manifest
  echo "Lot 4 setup OK: $ROOT"
}

status(){
  safe_root
  need_file "$ROOT/$MARKER"
  grep -Fxq "$SAFETY_MARKER" "$ROOT/$MARKER" || fail "invalid safety marker"
  verify_manifest
  [[ "$(fixture_count "$ROOT/source")" -eq 18 ]] || fail "expected exactly 18 source fixtures"
  echo "Lot 4 status OK: synthetic/offline response plan"
}

run_negative_tests(){
  local out="$ROOT/output/negative-results.csv"
  printf 'family,result,reason\n' > "$out"
  record(){ printf '%s,BLOCKED,%s\n' "$1" "$2" >> "$out"; }
  ! known_asset "AST-UNKNOWN" && record "unknown-asset" "containment option references unknown asset"
  ! known_impact "C-UNKNOWN" && record "missing-business-impact" "high-impact containment lacks business impact"
  [[ -z "" ]] && record "missing-approval-owner" "containment approval lacks authorized owner"
  [[ "AUTO_EXECUTE" != "APPROVED_FOR_SIMULATION" && "AUTO_EXECUTE" != "DEFERRED" && "AUTO_EXECUTE" != "REJECTED" ]] && record "auto-execute" "automatic live execution is forbidden"
  [[ "EXECUTED" != "NOT_EXECUTED" ]] && record "claimed-execution" "containment cannot be represented as executed"
  ! known_exit "EXIT-UNKNOWN" && record "missing-exit-criterion" "eradication action lacks exit criterion"
  ! known_rollback "RB-UNKNOWN" && record "missing-rollback" "eradication action lacks rollback"
  [[ "COMPLETE" != "PLANNED" && "COMPLETE" != "BLOCKED" && "COMPLETE" != "DEFERRED" ]] && record "eradication-complete" "eradication cannot be claimed complete"
  [[ -z "" ]] && record "trusted-state-no-proof" "trusted-state criterion lacks proof requirement"
  ! trusted_source "TS-001" && record "untrusted-restore-source" "restore source cannot rely on unproven trusted-state criterion"
  ! known_rollback "RB-MISSING" && record "recovery-no-rollback" "recovery plan lacks rollback"
  [[ "FAIL" == "FAIL" ]] && record "ignored-failed-test" "failed recovery test blocks readiness"
  ! known_reopen "RC-MISSING" && record "monitoring-no-reopen" "monitoring requires bounded reopen criterion"
  [[ "$DECISION" != "CLOSED" ]] && record "premature-closure" "case cannot be CLOSED with actions or NOT_TESTABLE evidence"
  [[ "$(awk -F, 'NR>1 && $2=="BLOCKED"{c++} END{print c+0}' "$out")" -eq 14 ]] || fail "expected fourteen blocked negative families"
}

run(){
  safe_root
  status >/dev/null
  rm -rf "$ROOT/output" "$ROOT/work"
  mkdir -p "$ROOT/output" "$ROOT/work/negative"
  cp "$ROOT/source-integrity.sha256" "$ROOT/output/source-integrity.sha256"

  printf 'option_id,asset_id,action,impact,evidence_basis,approval_required,approval_owner,decision,execution_status,reason,synthetic\n' > "$ROOT/output/containment-decision.csv"
  tail -n +2 "$ROOT/source/decisions/containment-options.csv" | while IFS=, read -r oid asset action impact basis approval_required default_decision synthetic; do
    known_asset "$asset" || fail "unknown containment asset: $asset"
    approval_owner="$(awk -F, -v id="$oid" 'NR>1 && $1==id {print $2; exit}' "$ROOT/source/decisions/containment-approvals.csv")"
    approval_status="$(awk -F, -v id="$oid" 'NR>1 && $1==id {print $3; exit}' "$ROOT/source/decisions/containment-approvals.csv")"
    [[ -n "$approval_owner" ]] || fail "missing approval owner: $oid"
    if [[ "$impact" = "HIGH" || "$impact" = "CRITICAL" ]]; then known_impact "$oid" || fail "missing business impact: $oid"; fi
    decision="$default_decision"; reason="approval-and-impact-reviewed"
    if [[ "$approval_status" != "APPROVED" ]]; then decision="DEFERRED"; reason="approval-pending"; fi
    printf '%s,%s,%s,%s,%s,%s,%s,%s,NOT_EXECUTED,%s,%s\n' "$oid" "$asset" "$action" "$impact" "$basis" "$approval_required" "$approval_owner" "$decision" "$reason" "$synthetic" >> "$ROOT/output/containment-decision.csv"
  done

  printf 'option_id,evidence_id,required_action,status,synthetic\n' > "$ROOT/output/evidence-protection-report.csv"
  tail -n +2 "$ROOT/source/evidence/protection.csv" >> "$ROOT/output/evidence-protection-report.csv"
  awk -F, 'NR>1 && ($2=="" || $3!="PRESERVE_BEFORE_ACTION" || $4!="READY"){bad=1} END{exit(bad?1:0)}' "$ROOT/output/evidence-protection-report.csv" || fail "evidence protection prerequisite missing"

  cp "$ROOT/source/eradication/actions.csv" "$ROOT/output/eradication-plan.csv"
  tail -n +2 "$ROOT/output/eradication-plan.csv" | while IFS=, read -r aid asset action pre exitid rollback status synthetic; do
    known_asset "$asset" || fail "unknown eradication asset: $asset"
    known_exit "$exitid" || fail "unknown exit criterion: $aid"
    known_rollback "$rollback" || fail "unknown rollback: $aid"
    case "$status" in PLANNED|BLOCKED|DEFERRED) ;; *) fail "invalid eradication status: $status";; esac
  done

  printf 'criterion_id,asset_id,criterion,proof_source,result,readiness,synthetic\n' > "$ROOT/output/recovery-readiness.csv"
  tail -n +2 "$ROOT/source/recovery/trusted-state.csv" | while IFS=, read -r cid asset criterion proof result synthetic; do
    known_asset "$asset" || fail "unknown trusted-state asset: $asset"
    [[ -n "$proof" ]] || fail "missing trusted-state proof: $cid"
    case "$result" in PASS) readiness="READY_CRITERION" ;; NOT_TESTABLE) readiness="ACTION_REQUIRED" ;; FAIL) readiness="BLOCKED" ;; *) fail "invalid trusted-state result: $result" ;; esac
    printf '%s,%s,%s,%s,%s,%s,%s\n' "$cid" "$asset" "$criterion" "$proof" "$result" "$readiness" "$synthetic" >> "$ROOT/output/recovery-readiness.csv"
  done

  tail -n +2 "$ROOT/source/recovery/restore-plan.csv" | while IFS=, read -r pid asset source trust rollback status synthetic; do
    known_asset "$asset" || fail "unknown recovery asset: $asset"
    known_asset "$source" || fail "unknown restore source: $source"
    trusted_source "$trust" || fail "restore source trust criterion not PASS: $pid"
    known_rollback "$rollback" || fail "missing recovery rollback: $pid"
  done

  cp "$ROOT/source/recovery/recovery-tests.csv" "$ROOT/output/recovery-test-results.csv"
  awk -F, 'NR>1 && $5=="FAIL"{bad=1} END{exit(bad?1:0)}' "$ROOT/output/recovery-test-results.csv" || fail "recovery test failure blocks readiness"
  grep -Fq ',endpoint-edr,NOT_TESTABLE,SYNTHETIC' "$ROOT/output/recovery-test-results.csv" || fail "endpoint-edr NOT_TESTABLE gap must remain explicit"

  printf 'monitor_id,signal,window,owner,expected_state,reopen_criterion,reopen_condition,synthetic\n' > "$ROOT/output/monitoring-plan.csv"
  tail -n +2 "$ROOT/source/monitoring/post-recovery-monitoring.csv" | while IFS=, read -r mid signal window owner expected reopen synthetic; do
    [[ -n "$window" && -n "$owner" ]] || fail "unbounded monitoring row: $mid"
    known_reopen "$reopen" || fail "unknown reopen criterion: $mid"
    condition="$(awk -F, -v id="$reopen" 'NR>1 && $1==id {print $2; exit}' "$ROOT/source/monitoring/reopen-criteria.csv")"
    printf '%s,%s,%s,%s,%s,%s,%s,%s\n' "$mid" "$signal" "$window" "$owner" "$expected" "$reopen" "$condition" "$synthetic" >> "$ROOT/output/monitoring-plan.csv"
  done

  cat > "$ROOT/output/decision-log.csv" <<'EOF'
decision_id,owner,decision,status,basis,synthetic
D-001,secops-owner,containment-options-reviewed,PLANNED,investigation-findings,SYNTHETIC
D-002,identity-owner,identity-containment-deferred,DEFERRED,approval-pending,SYNTHETIC
D-003,app-owner,recovery-plan-prepared,PLANNED,trusted-state-and-tests,SYNTHETIC
D-004,business-owner,case-closure,DEFERRED,actions-and-endpoint-evidence-remain,SYNTHETIC
EOF
  run_negative_tests
  cat > "$ROOT/output/case-summary.md" <<'EOF'
# CASE-IR-004 — synthetic response plan

- Scope: containment, eradication and recovery planning only.
- Containment: decisions are represented; execution status is always NOT_EXECUTED.
- Evidence: required preservation prerequisites remain explicit before represented actions.
- Eradication: actions are PLANNED or DEFERRED and carry exit criteria plus rollback.
- Recovery: trusted-state criteria and represented tests are checked before readiness.
- Endpoint evidence: `endpoint-edr` remains `NOT_TESTABLE`.
- Monitoring: bounded windows and reopen criteria are mandatory.
- Closure: deferred. This lab does not close a real incident.
EOF
  cat > "$ROOT/output/proof-boundaries.md" <<'EOF'
# Proof boundaries

CI proves deterministic processing of synthetic fixtures only.

It does not prove real containment, account disablement, firewall enforcement, eradication, malware removal, backup integrity, restore success, endpoint health, recurrence absence, legal authority, business approval, or final incident closure.

SIMULATION_ONLY_NO_LIVE_ACTIONS
EOF
  printf '%s\n' "$DECISION" > "$ROOT/output/decision.txt"
  echo "Lot 4 run OK: $DECISION"
}

validate(){
  safe_root; status >/dev/null
  required=(containment-decision.csv evidence-protection-report.csv eradication-plan.csv recovery-readiness.csv recovery-test-results.csv monitoring-plan.csv decision-log.csv source-integrity.sha256 negative-results.csv case-summary.md proof-boundaries.md decision.txt)
  for f in "${required[@]}"; do [[ -s "$ROOT/output/$f" ]] || fail "missing output: $f"; done
  grep -Fq 'CASE-IR-004' "$ROOT/output/case-summary.md" || fail "wrong case ID"
  [[ "$(awk -F, 'NR>1{c++} END{print c+0}' "$ROOT/output/containment-decision.csv")" -eq 3 ]] || fail "expected three containment options"
  awk -F, 'NR>1 && $9!="NOT_EXECUTED"{bad=1} END{exit(bad?1:0)}' "$ROOT/output/containment-decision.csv" || fail "live containment execution represented"
  awk -F, 'NR>1 && $4=="HIGH" && ($7=="" || $8==""){bad=1} END{exit(bad?1:0)}' "$ROOT/output/containment-decision.csv" || fail "high impact containment lacks approval"
  awk -F, 'NR>1 && ($5=="" || $6==""){bad=1} END{exit(bad?1:0)}' "$ROOT/output/eradication-plan.csv" || fail "eradication lacks exit or rollback"
  awk -F, 'NR>1 && $7!="PLANNED" && $7!="BLOCKED" && $7!="DEFERRED"{bad=1} END{exit(bad?1:0)}' "$ROOT/output/eradication-plan.csv" || fail "eradication claims completion"
  grep -Fq 'endpoint-edr,NOT_TESTABLE,ACTION_REQUIRED,SYNTHETIC' "$ROOT/output/recovery-readiness.csv" || fail "endpoint trusted-state limitation missing"
  grep -Fq ',endpoint-edr,NOT_TESTABLE,SYNTHETIC' "$ROOT/output/recovery-test-results.csv" || fail "endpoint recovery test limitation missing"
  awk -F, 'NR>1 && ($3=="" || $4=="" || $6=="" || $7==""){bad=1} END{exit(bad?1:0)}' "$ROOT/output/monitoring-plan.csv" || fail "monitoring row incomplete"
  [[ "$(awk -F, 'NR>1 && $2=="BLOCKED"{c++} END{print c+0}' "$ROOT/output/negative-results.csv")" -eq 14 ]] || fail "negative family count mismatch"
  [[ "$(cat "$ROOT/output/decision.txt")" = "$DECISION" ]] || fail "wrong final decision"
  grep -Fq "$SAFETY_MARKER" "$ROOT/output/proof-boundaries.md" || fail "safety proof boundary missing"
  verify_manifest
  echo "Lot 4 validation PASS: $DECISION"
}

reset(){ safe_root; rm -rf -- "$ROOT"; echo "Lot 4 reset OK: $ROOT"; }

case "$MODE" in setup) setup ;; status) status ;; run) run ;; validate) validate ;; reset) reset ;; *) fail "usage: $0 {setup|status|run|validate|reset} ROOT" ;; esac
