#!/usr/bin/env bash

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly ROOT
readonly RESULTS="${ROOT}/results"
readonly IMAGE="serein-arch-02-composition"

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 expected_exit="$2"
  shift 2

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

  mkdir -p "${directory}"
  {
    printf '%q' "$1"
    for argument in "${@:2}"; do
      printf ' %q' "${argument}"
    done
    printf '\n'
  } >"${directory}/command.txt"

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

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

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

  if [[ ${actual_exit} -ne ${expected_exit} ]]; then
    echo "FAILED: ${name} exited ${actual_exit}; expected ${expected_exit}" >&2
    return 1
  fi

  printf '%-48s exit %s as expected\n' "${name}" "${actual_exit}"
}

in_container() {
  docker run --rm \
    --volume "${RESULTS}:/experiment/results" \
    "${IMAGE}" \
    "$@"
}

behavior() {
  local evidence_path="$1"
  local flow="$2"
  local provider_schema="$3"
  local adapter_schema="$4"
  local located_entry="$5"

  docker run --rm \
    --volume "${RESULTS}:/experiment/results" \
    --env "EVIDENCE_DIR=/experiment/results/${evidence_path}" \
    --env "FLOW=${flow}" \
    --env "PROVIDER_SCHEMA=${provider_schema}" \
    --env "ADAPTER_SCHEMA=${adapter_schema}" \
    --env "LOCATED_ENTRY=${located_entry}" \
    "${IMAGE}" \
    bin/test-with-provider.sh \
    php vendor/bin/phpunit --configuration phpunit.xml
}

resolution() {
  local resolution_case="$1"
  local explicit_binding="$2"
  local located_entry="$3"

  docker run --rm \
    --env "RESOLUTION_CASE=${resolution_case}" \
    --env "EXPLICIT_BINDING=${explicit_binding}" \
    --env "LOCATED_ENTRY=${located_entry}" \
    "${IMAGE}" \
    php vendor/bin/phpunit --configuration phpunit-resolution.xml
}

source_diff() {
  in_container diff -u "$1" "$2"
}

rm -rf \
  "${RESULTS}/analysis" \
  "${RESULTS}/behavior" \
  "${RESULTS}/comparison" \
  "${RESULTS}/diffs" \
  "${RESULTS}/environment" \
  "${RESULTS}/resolution" \
  "${RESULTS}/setup"
mkdir -p "${RESULTS}"

capture setup/build 0 docker build --tag "${IMAGE}" .
capture environment/php 0 in_container php --version
capture environment/composer-version 0 in_container composer --version
capture environment/packages 0 in_container composer show --locked --direct --no-ansi
capture environment/composer-audit 0 in_container composer audit --locked --no-ansi --no-interaction

capture behavior/explicit-v1-provider-v1 0 \
  behavior behavior/explicit-v1-provider-v1 explicit v1 v1 v1
capture behavior/explicit-v1-provider-v2 1 \
  behavior behavior/explicit-v1-provider-v2 explicit v2 v1 v1
capture behavior/explicit-v2-provider-v2 0 \
  behavior behavior/explicit-v2-provider-v2 explicit v2 v2 v1
capture behavior/located-v2-provider-v2 0 \
  behavior behavior/located-v2-provider-v2 located v2 v1 v2

capture resolution/explicit-present 0 resolution explicit-present present v1
capture resolution/explicit-missing 0 resolution explicit-missing missing v1
capture resolution/located-invalid 0 resolution located-invalid present invalid

capture analysis/composition 0 in_container php analyze.php clean
capture analysis/locator-defect 1 in_container php analyze.php locator-defect
capture analysis/provider-registration-defect 1 \
  in_container php analyze.php provider-registration-defect
capture analysis/binding-defect 1 in_container php analyze.php binding-defect

capture diffs/adapters 1 source_diff \
  app/Infrastructure/V1HttpProductPrices.php \
  app/Infrastructure/V2HttpProductPrices.php
capture diffs/explicit-vs-located 1 source_diff \
  app/Application/QuoteProduct.php \
  app/Located/LocatedQuoteProduct.php

capture comparison 0 in_container php compare.php

echo "Evidence retained in ${RESULTS}"
