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

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)"
backend_script="${repo_root}/scripts/ci-backend-required.sh"
test_dir="$(mktemp -d)"
trap 'rm -rf "${test_dir}"' EXIT

mkdir -p "${test_dir}/bin" "${test_dir}/state"
cat >"${test_dir}/bin/go" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

command="${1:-}"
case "${command}" in
  list)
    [[ "${2:-}" == "./..." ]]
    printf '%s\n' "${BACKEND_SCHEDULER_TEST_GO_LIST_OUTPUT:-}"
    ;;
  test)
    package="${2:-}"
    case "${package}" in
  slow)
    touch "${BACKEND_SCHEDULER_TEST_STATE}/slow-started"
    for _ in $(seq 1 250); do
      [[ ! -f "${BACKEND_SCHEDULER_TEST_STATE}/release-slow" ]] || break
      sleep 0.02
    done
    [[ -f "${BACKEND_SCHEDULER_TEST_STATE}/release-slow" ]]
    touch "${BACKEND_SCHEDULER_TEST_STATE}/slow-finished"
    ;;
  fast)
    for _ in $(seq 1 250); do
      [[ ! -f "${BACKEND_SCHEDULER_TEST_STATE}/slow-started" ]] || break
      sleep 0.02
    done
    [[ -f "${BACKEND_SCHEDULER_TEST_STATE}/slow-started" ]]
    touch "${BACKEND_SCHEDULER_TEST_STATE}/fast-started"
    sleep 0.2
    touch "${BACKEND_SCHEDULER_TEST_STATE}/fast-finished"
    ;;
  next)
    [[ -f "${BACKEND_SCHEDULER_TEST_STATE}/fast-finished" ]]
    [[ ! -f "${BACKEND_SCHEDULER_TEST_STATE}/slow-finished" ]] &&
      touch "${BACKEND_SCHEDULER_TEST_STATE}/next-started-before-slow-finished"
    touch "${BACKEND_SCHEDULER_TEST_STATE}/release-slow"
    ;;
  failing)
    exit 7
    ;;
  after-failure)
    touch "${BACKEND_SCHEDULER_TEST_STATE}/after-failure-ran"
    ;;
  noop)
    :
    ;;
  timing-env)
    [[ "${AGENTTEAM_TIDB_TEST_TIMING:-}" == "1" ]]
    [[ -n "${AGENTTEAM_TIDB_TEST_TIMING_FILE:-}" ]]
    printf '[tidb:testkit:timing] test="fake" operation=clone_database status=passed duration_ms=1\n' \
      >>"${AGENTTEAM_TIDB_TEST_TIMING_FILE}"
    touch "${BACKEND_SCHEDULER_TEST_STATE}/timing-env-enabled"
    ;;
  github.com/tidbcloud/AgentTeam/internal/service/extensionflow)
    previous=""
    for argument in "$@"; do
      if [[ "${previous}" == "-run" ]]; then
        printf '%s\n' "${argument}" \
          >>"${BACKEND_SCHEDULER_TEST_STATE}/service-extension-run-order"
      fi
      previous="${argument}"
    done
    ;;
  *)
    echo "unexpected fake go package: ${package}" >&2
    exit 2
    ;;
    esac
    ;;
  *)
    echo "unexpected fake go command: ${command}" >&2
    exit 2
    ;;
esac
EOF
chmod +x "${test_dir}/bin/go"

export BACKEND_SCHEDULER_TEST_STATE="${test_dir}/state"
export PATH="${test_dir}/bin:${PATH}"
export BACKEND_SCHEDULER_TEST_GO_LIST_OUTPUT=$'github.com/tidbcloud/AgentTeam/internal/api\ngithub.com/tidbcloud/AgentTeam/presets'

(
  source "${backend_script}"
  shard_packages() {
    printf '%s\n' slow fast next
  }
  shard_split_tests() {
    :
  }
  AGENTTEAM_BACKEND_PACKAGE_BATCH_SIZE=1 AGENTTEAM_BACKEND_SHARD_JOB_P=2 run_shard scheduler-test
) >"${test_dir}/dynamic.log"

[[ -f "${test_dir}/state/next-started-before-slow-finished" ]]
[[ "$(grep -cF '[backend:timing] event=start' "${test_dir}/dynamic.log")" -eq 3 ]]
[[ "$(grep -cF '[backend:timing] event=finish' "${test_dir}/dynamic.log")" -eq 3 ]]
grep -F 'job=packages:next status=0' "${test_dir}/dynamic.log" >/dev/null

set +e
(
  source "${backend_script}"
  shard_packages() {
    printf '%s\n' failing after-failure
  }
  shard_split_tests() {
    :
  }
  AGENTTEAM_BACKEND_PACKAGE_BATCH_SIZE=1 AGENTTEAM_BACKEND_SHARD_JOB_P=1 run_shard scheduler-test
) >"${test_dir}/failure.log" 2>&1
failure_status=$?
set -e

[[ "${failure_status}" -ne 0 ]]
[[ -f "${test_dir}/state/after-failure-ran" ]]
grep -F 'job=packages:failing status=7' "${test_dir}/failure.log" >/dev/null

actual_order="$({
  source "${backend_script}"
  shard_packages store-domains
})"
actual_heavy_prefix="$(printf '%s\n' "${actual_order}" | head -n 3)"
expected_heavy_prefix=$'github.com/tidbcloud/AgentTeam/internal/store/agent\ngithub.com/tidbcloud/AgentTeam/internal/store/agentops\ngithub.com/tidbcloud/AgentTeam/internal/store/extension'
[[ "${actual_heavy_prefix}" == "${expected_heavy_prefix}" ]]
[[ "${actual_order}" == *$'github.com/tidbcloud/AgentTeam/internal/store/workflow/run\ngithub.com/tidbcloud/AgentTeam/internal/store/access'* ]]
heavy_order="$(printf '%s\n' "${actual_order}" | sed -n '1,/\/workflow\/run$/p')"
normal_order="$(printf '%s\n' "${actual_order}" | sed '1,/\/workflow\/run$/d')"
printf '%s\n' "${heavy_order}" | LC_ALL=C sort -c
printf '%s\n' "${normal_order}" | LC_ALL=C sort -c

actual_coredb_splits="$({
  source "${backend_script}"
  shard_split_tests coredb-and-tidb
})"
expected_coredb_splits=$''
[[ "${actual_coredb_splits}" == "${expected_coredb_splits}" ]]

backend_packages="$({
  source "${backend_script}"
  list_backend_packages
})"
printf '%s\n' "${backend_packages}" | grep -Fx 'github.com/tidbcloud/AgentTeam/books/_infra/scripts/plancheck' >/dev/null
! printf '%s\n' "${backend_packages}" | grep -Fx 'github.com/tidbcloud/AgentTeam/books/workflow-tuts/scripts/plancheck' >/dev/null

actual_api_core="$({
  source "${backend_script}"
  shard_packages api-core
})"
if printf '%s\n' "${actual_api_core}" |
  grep -Fx 'github.com/tidbcloud/AgentTeam/internal/service/extensionflow' >/dev/null; then
  echo 'service/extensionflow must not remain in the api-core regular package batch' >&2
  exit 1
fi

actual_api_support_splits="$({
  source "${backend_script}"
  shard_split_tests api-support
})"
expected_api_support_splits=$'github.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^Test[AW]\ngithub.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^TestC\ngithub.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^Test[BIK]\ngithub.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^Test[ER]\ngithub.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^Test[MPS]\ngithub.com/tidbcloud/AgentTeam/internal/service/extensionflow\t^TestT'
if [[ "${actual_api_support_splits}" != "${expected_api_support_splits}" ]]; then
  echo 'api-support split groups must remain AW / C / BIK / ER / MPS / T' >&2
  exit 1
fi

(
  source "${backend_script}"
  shard_packages() {
    printf '%s\n' noop
  }
  shard_split_tests() {
    printf '%s\t%s\n' \
      github.com/tidbcloud/AgentTeam/internal/service/extensionflow \
      '^Test[AW]'
  }
  run_nested_module_tests() {
    :
  }
  AGENTTEAM_BACKEND_SHARD_JOB_P=1 run_shard api-support
) >"${test_dir}/service-extension.log"
actual_service_extension_run_order="$(
  cat "${test_dir}/state/service-extension-run-order"
)"
expected_service_extension_run_order=$'^TestA\n^TestW'
if [[ "${actual_service_extension_run_order}" != \
  "${expected_service_extension_run_order}" ]]; then
  echo 'api-support AW split must finish A before starting W' >&2
  exit 1
fi

(
  source "${backend_script}"
  shard_packages() {
    printf '%s\n' timing-env
  }
  shard_split_tests() {
    :
  }
  AGENTTEAM_BACKEND_PACKAGE_BATCH_SIZE=1 AGENTTEAM_BACKEND_SHARD_JOB_P=1 run_shard store-domains
) >"${test_dir}/timing-env.log"
[[ -f "${test_dir}/state/timing-env-enabled" ]]
grep -F '[tidb:testkit:timing] test="fake" operation=clone_database status=passed duration_ms=1' \
  "${test_dir}/timing-env.log" >/dev/null

rm -f "${test_dir}/state/timing-env-enabled"
(
  source "${backend_script}"
  shard_packages() {
    printf '%s\n' timing-env timing-env
  }
  shard_split_tests() {
    :
  }
  AGENTTEAM_BACKEND_SHARD_JOB_P=1 run_shard api-core
) >"${test_dir}/api-core-batching.log"
[[ -f "${test_dir}/state/timing-env-enabled" ]]
[[ "$(grep -cF '[backend:timing] event=start' "${test_dir}/api-core-batching.log")" -eq 2 ]]

echo 'backend required scheduler tests passed'
