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

ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
HROOT="$ROOT_DIR/tests/haskell_upstream"
CORPUS_ROOT="$HROOT/Duckling"
TEST_ROOT="$HROOT/tests/Duckling"
MANIFEST="$HROOT/porting_manifest.tsv"
TEST_MODULE_MANIFEST="$HROOT/test_module_manifest.tsv"
STATUS_MD="$HROOT/PORTING_STATUS.md"
PENDING_TSV="$HROOT/pending_corpus.tsv"
PORTED_TSV="$HROOT/ported_corpus.tsv"
PENDING_TEST_MODULES_TSV="$HROOT/pending_test_modules.tsv"
PORTED_TEST_MODULES_TSV="$HROOT/ported_test_modules.tsv"

if [[ ! -d "$CORPUS_ROOT" ]]; then
  echo "Missing corpus root: $CORPUS_ROOT" >&2
  exit 1
fi

tmp_manifest="$(mktemp)"
tmp_stats="$(mktemp)"
tmp_represented_refs="$(mktemp)"
tmp_semantic_refs="$(mktemp)"
tmp_progress="$(mktemp)"
tmp_hs_represented_refs="$(mktemp)"
trap 'rm -f "$tmp_manifest" "$tmp_stats" "$tmp_represented_refs" "$tmp_semantic_refs" "$tmp_progress" "$tmp_hs_represented_refs"' EXIT

find "$CORPUS_ROOT" -type f -name 'Corpus.hs' | sort | while IFS= read -r f; do
  rel="${f#"$CORPUS_ROOT/"}"
  IFS='/' read -r -a parts <<< "$rel"

  dim="${parts[0]}"
  lang="COMMON"
  locale="-"

  if [[ "${#parts[@]}" -ge 3 ]] && [[ "${parts[1]}" =~ ^[A-Z]{2}$ ]]; then
    lang="${parts[1]}"
  fi
  if [[ "${#parts[@]}" -ge 4 ]] && [[ "${parts[2]}" =~ ^[A-Z]{2}$ ]]; then
    locale="${parts[2]}"
  fi

  printf "%s\t%s\t%s\t%s\n" "$dim" "$lang" "$locale" "$rel"
done > "$tmp_manifest"

cp "$tmp_manifest" "$MANIFEST"
find "$HROOT/tests" -type f -name '*.hs' | sort | sed "s#^$HROOT/tests/##" > "$TEST_MODULE_MANIFEST"

# Detect corpus files represented by any Rust test file.
rg -o --no-filename 'Duckling/[A-Za-z0-9_/-]+/Corpus\.hs' "$ROOT_DIR/tests" -g '*.rs' \
  | sort -u > "$tmp_represented_refs" || true

# Detect corpus files with semantic assertions (exclude the generated pending placeholder suite).
rg -o --no-filename 'Duckling/[A-Za-z0-9_/-]+/Corpus\.hs' "$ROOT_DIR/tests" -g '*.rs' -g '!pending_corpus.rs' \
  | sort -u > "$tmp_semantic_refs" || true

# Detect imported Haskell test modules represented by Rust tests.
rg -o --no-filename '(Duckling/[A-Za-z0-9_/-]+|TestMain)\.hs' "$ROOT_DIR/tests" -g '*.rs' \
  | sort -u > "$tmp_hs_represented_refs" || true

# Expand manifest with representation + semantic status columns.
while IFS=$'\t' read -r dim lang locale rel; do
  ref="Duckling/$rel"
  represented_status="missing"
  semantic_status="pending"

  if grep -Fxq "$ref" "$tmp_represented_refs"; then
    represented_status="represented"
  fi
  if grep -Fxq "$ref" "$tmp_semantic_refs"; then
    semantic_status="semantic"
  fi

  printf "%s\t%s\t%s\t%s\t%s\t%s\n" \
    "$dim" "$lang" "$locale" "$rel" "$represented_status" "$semantic_status"
done < "$MANIFEST" > "$tmp_progress"

awk -F'\t' '$6=="pending"{print $1 "\t" $2 "\t" $3 "\t" $4}' "$tmp_progress" > "$PENDING_TSV"
awk -F'\t' '$6=="semantic"{print $1 "\t" $2 "\t" $3 "\t" $4}' "$tmp_progress" > "$PORTED_TSV"

grep -Fvx -f "$tmp_hs_represented_refs" "$TEST_MODULE_MANIFEST" > "$PENDING_TEST_MODULES_TSV" || true
grep -Fx -f "$tmp_hs_represented_refs" "$TEST_MODULE_MANIFEST" > "$PORTED_TEST_MODULES_TSV" || true

total_corpus="$(wc -l < "$MANIFEST" | tr -d ' ')"
total_hs_tests="$(find "$HROOT/tests" -type f -name '*.hs' | wc -l | tr -d ' ')"
total_rust_corpus_tests="$(find "$ROOT_DIR/tests" -maxdepth 1 -type f -name '*_corpus.rs' | wc -l | tr -d ' ')"
total_hs_tests_represented="$(wc -l < "$PORTED_TEST_MODULES_TSV" | tr -d ' ')"
total_hs_tests_pending="$((total_hs_tests - total_hs_tests_represented))"
total_dims="$(cut -f1 "$MANIFEST" | sort -u | wc -l | tr -d ' ')"
total_represented_corpus="$(awk -F'\t' '$5=="represented"{c++} END{print c+0}' "$tmp_progress")"
total_semantic_corpus="$(awk -F'\t' '$6=="semantic"{c++} END{print c+0}' "$tmp_progress")"
total_pending_semantic="$((total_corpus - total_semantic_corpus))"

{
  echo "# Duckling Porting Status"
  echo
  echo "Generated by \`scripts/update_porting_status.sh\`."
  echo
  echo "## Summary"
  echo
  echo "- Haskell corpus files imported: **$total_corpus**"
  echo "- Haskell test modules imported: **$total_hs_tests**"
  echo "- Haskell test modules represented in Rust tests (any): **$total_hs_tests_represented**"
  echo "- Haskell test modules pending representation: **$total_hs_tests_pending**"
  echo "- Dimensions present in corpus: **$total_dims**"
  echo "- Rust corpus test files currently in repo: **$total_rust_corpus_tests**"
  echo "- Corpus files represented in Rust tests (any): **$total_represented_corpus**"
  echo "- Corpus files with semantic Rust assertions: **$total_semantic_corpus**"
  echo "- Corpus files pending semantic assertion port: **$total_pending_semantic**"
  echo
  echo "## Dimension Coverage"
  echo
  echo '| Dimension | Corpus Files | Represented | Semantic | Pending Semantic | HS Tests | Languages | Locales | Rust `<dim>_corpus.rs` |'
  echo "|---|---:|---:|---:|---:|---:|---:|---:|---|"
} > "$STATUS_MD"

while IFS= read -r dim; do
  corpus_count="$(awk -F'\t' -v d="$dim" '$1==d { c++ } END { print c+0 }' "$MANIFEST")"
  represented_count="$(awk -F'\t' -v d="$dim" '$1==d && $5=="represented" { c++ } END { print c+0 }' "$tmp_progress")"
  semantic_count="$(awk -F'\t' -v d="$dim" '$1==d && $6=="semantic" { c++ } END { print c+0 }' "$tmp_progress")"
  pending_count="$((corpus_count - semantic_count))"
  hs_test_count="0"
  if [[ -d "$TEST_ROOT/$dim" ]]; then
    hs_test_count="$(find "$TEST_ROOT/$dim" -type f -name 'Tests.hs' | wc -l | tr -d ' ')"
  fi
  lang_count="$(awk -F'\t' -v d="$dim" '$1==d { seen[$2]=1 } END { for (k in seen) c++; print c+0 }' "$MANIFEST")"
  locale_count="$(awk -F'\t' -v d="$dim" '$1==d && $3 != "-" { seen[$2 FS $3]=1 } END { for (k in seen) c++; print c+0 }' "$MANIFEST")"

  snake="$(echo "$dim" | sed -E 's/([A-Z])/_\1/g' | tr '[:upper:]' '[:lower:]' | sed -E 's/^_//')"
  rust_test_path="$ROOT_DIR/tests/${snake}_corpus.rs"
  rust_status="no"
  if [[ -f "$rust_test_path" ]]; then
    rust_status="yes"
  fi

  printf "| %s | %s | %s | %s | %s | %s | %s | %s | %s |\n" \
    "$dim" \
    "$corpus_count" \
    "$represented_count" \
    "$semantic_count" \
    "$pending_count" \
    "$hs_test_count" \
    "$lang_count" \
    "$locale_count" \
    "$rust_status" >> "$STATUS_MD"

  printf "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n" \
    "$dim" \
    "$corpus_count" \
    "$represented_count" \
    "$semantic_count" \
    "$pending_count" \
    "$hs_test_count" \
    "$lang_count" \
    "$locale_count" \
    "$rust_status" >> "$tmp_stats"
done < <(cut -f1 "$MANIFEST" | sort -u)

{
  echo
  echo "## Recommended Queue"
  echo
  echo "| Priority | Dimension | Why |"
  echo "|---:|---|---|"
} >> "$STATUS_MD"

priority=1
while IFS=$'\t' read -r dim _corpus_count _represented_count _semantic_count pending_count _hs_test_count lang_count locale_count rust_status; do
  reason="largest pending corpus backlog"
  if [[ "$rust_status" == "no" ]]; then
    reason="missing Rust base corpus test file"
  elif [[ "$pending_count" -le 1 ]]; then
    reason="near complete corpus coverage"
  elif [[ "$lang_count" -gt 1 ]] || [[ "$locale_count" -gt 0 ]]; then
    reason="multilingual/locale backlog"
  fi

  printf "| %s | %s | %s |\n" "$priority" "$dim" "$reason" >> "$STATUS_MD"
  priority=$((priority + 1))
done < <(sort -t$'\t' -k5,5nr -k7,7nr -k8,8nr -k2,2nr "$tmp_stats")

{
  echo
  echo "## Manifest"
  echo
  echo "Raw entries are in \`tests/haskell_upstream/porting_manifest.tsv\` with columns:"
  echo
  echo "1. Dimension"
  echo '2. Language (`COMMON` when shared)'
  echo '3. Locale (`-` when none)'
  echo "4. Relative corpus path"
  echo
  echo "Additional files:"
  echo
  echo "1. \`tests/haskell_upstream/pending_corpus.tsv\`"
  echo "2. \`tests/haskell_upstream/ported_corpus.tsv\`"
  echo "3. \`tests/haskell_upstream/test_module_manifest.tsv\`"
  echo "4. \`tests/haskell_upstream/pending_test_modules.tsv\`"
  echo "5. \`tests/haskell_upstream/ported_test_modules.tsv\`"
} >> "$STATUS_MD"

echo "Wrote:"
echo "  $MANIFEST"
echo "  $STATUS_MD"
echo "  $PENDING_TSV"
echo "  $PORTED_TSV"
echo "  $TEST_MODULE_MANIFEST"
echo "  $PENDING_TEST_MODULES_TSV"
echo "  $PORTED_TEST_MODULES_TSV"
