#!/usr/bin/env bash

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly ROOT
readonly RESULTS="${ROOT}/results"
readonly IMAGE="serein-obj-01-php"

if [[ "${RESULTS}" != "${ROOT}/results" ]]; then
  echo "refusing to clear an unexpected results directory" >&2
  exit 65
fi

cd "${ROOT}"

milliseconds() {
  perl -MTime::HiRes=time -e 'printf "%.0f\n", time * 1000'
}

capture() {
  local name="$1"
  local expectation="$2"
  shift 2

  local directory="${RESULTS}/${name}"
  local started
  local finished
  local exit_code

  mkdir -p "${directory}"
  printf '%q ' "$@" \
    | sed -E 's/[[:space:]]+$//' >"${directory}/command.txt"
  printf '\n' >>"${directory}/command.txt"

  started="$(milliseconds)"
  set +e
  "$@" >"${directory}/output.txt.tmp" 2>&1
  exit_code=$?
  set -e
  finished="$(milliseconds)"

  sed -E -e 's/[[:space:]]+$//' -e '${/^$/d;}' \
    "${directory}/output.txt.tmp" >"${directory}/output.txt"
  rm "${directory}/output.txt.tmp"

  {
    printf 'expectation=%s\n' "${expectation}"
    printf 'exit_code=%s\n' "${exit_code}"
    printf 'duration_ms=%s\n' "$((finished - started))"
  } >"${directory}/metadata.txt"

  if [[ "${expectation}" == "pass" && ${exit_code} -ne 0 ]]; then
    echo "FAILED: ${name} should have passed" >&2
    return 1
  fi

  if [[ "${expectation}" == "fail" && ${exit_code} -eq 0 ]]; then
    echo "FAILED: ${name} should have detected the counterfactual" >&2
    return 1
  fi

  printf '%-58s expected %s (exit %s)\n' \
    "${name}" "${expectation}" "${exit_code}"
}

mutation_case() {
  local name="$1"
  local suite="$2"
  local filter="$3"
  local temporary
  local source

  temporary="$(mktemp -d)"
  capture "mutations/${name}/generate" pass \
    php mutate.php "${name}" "${temporary}"
  # shellcheck disable=SC2016
  source="$(php -r '
    $data = json_decode(file_get_contents($argv[1]), true, 512, JSON_THROW_ON_ERROR);
    echo $data["source"];
  ' "${RESULTS}/mutations/${name}/generate/output.txt")"
  capture "diffs/${name}" fail \
    diff -u \
      --label "${source} (clean)" \
      --label "${source} (${name})" \
      "${ROOT}/src/${source}" \
      "${temporary}/src/${source}"
  capture "negative/${name}" fail \
    docker run --rm \
      --volume "${temporary}/src:/experiment/src:ro" \
      "${IMAGE}" \
      php vendor/bin/phpunit --testsuite="${suite}" --filter="${filter}"
  rm -rf "${temporary}"
}

rm -rf \
  "${RESULTS}/environment" \
  "${RESULTS}/positive" \
  "${RESULTS}/mutations" \
  "${RESULTS}/diffs" \
  "${RESULTS}/negative" \
  "${RESULTS}/analysis" \
  "${RESULTS}/sources" \
  "${RESULTS}/provenance" \
  "${RESULTS}/verification" \
  "${RESULTS}/setup"
mkdir -p "${RESULTS}"

capture setup/build pass docker build --tag "${IMAGE}" .
capture environment/php pass docker run --rm "${IMAGE}" php --version
capture environment/packages pass docker run --rm "${IMAGE}" php bin/versions.php
capture environment/composer-audit pass \
  docker run --rm "${IMAGE}" composer audit --locked --no-interaction
capture positive/construction pass \
  docker run --rm "${IMAGE}" php vendor/bin/phpunit --testsuite=Construction
capture positive/factory pass \
  docker run --rm "${IMAGE}" php vendor/bin/phpunit --testsuite=Factory
capture positive/hydration pass \
  docker run --rm "${IMAGE}" php vendor/bin/phpunit --testsuite=Hydration
capture positive/all pass \
  docker run --rm "${IMAGE}" php vendor/bin/phpunit --testsuite=All

mutation_case allow-zero-day-trial Construction zero_day_trial
mutation_case trial-end-one-day-short Construction trial_construction
mutation_case trial-gets-active-status Construction trial_construction
mutation_case allow-active-trial-end Construction reconstitution_refuses
mutation_case omit-trial-started-event Construction trial_construction
mutation_case reconstitution-records-started-event Construction reconstitution_retains
mutation_case reconstitution-recalculates-trial-end Construction reconstitution_retains
mutation_case factory-always-starts-paid Factory factory_selects
mutation_case factory-reads-clock-twice Factory factory_selects
mutation_case factory-generates-id-before-plan Factory unknown_plan
mutation_case catalog-failure-becomes-unknown-plan Factory catalog_failure
mutation_case mapper-forces-trial-status Hydration mapping_failure
mutation_case eloquent-row-requires-constructor-input Hydration eloquent_hydrates

capture analysis/construction-boundary pass \
  docker run --rm "${IMAGE}" php analyze.php
capture sources/primary pass \
  docker run --rm "${IMAGE}" php source-evidence.php
capture provenance/manifest pass \
  docker run --rm "${IMAGE}" php source-manifest.php
capture verification/results pass \
  docker run --rm \
    --volume "${RESULTS}:/experiment/results" \
    "${IMAGE}" \
    php verify-results.php

echo "OBJ-01 evidence retained in ${RESULTS}"
