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

repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
cd "$repo_root"

spec_path="specs/api/internal-api-clean-code-design.md"
if [[ ! -f "$spec_path" ]]; then
  echo "FAIL: missing canonical spec: $spec_path" >&2
  exit 1
fi

if ! command -v rg >/dev/null 2>&1; then
  echo "FAIL: ripgrep (rg) is required" >&2
  exit 2
fi

tmp_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_dir"' EXIT
status=0

section() {
  printf '\n== %s ==\n' "$1"
}

api_rg() {
  local pattern="$1"
  rg -n \
    --glob '*.go' \
    --glob '!*_test.go' \
    --glob '!internal/api/testkit/**' \
    "$pattern" internal/api
}

count_lines() {
  if [[ -s "$1" ]]; then
    wc -l < "$1" | tr -d '[:space:]'
  else
    printf '0'
  fi
}

check_zero() {
  local label="$1"
  local pattern="$2"
  local hits="$tmp_dir/check-zero.txt"

  if api_rg "$pattern" > "$hits"; then
    local count
    count="$(count_lines "$hits")"
    if [[ "$count" != "0" ]]; then
      echo "FAIL: $label count=$count"
      sed -n '1,40p' "$hits"
      status=1
      return
    fi
  fi

  echo "OK: $label count=0"
}

section "Canonical spec"
echo "$spec_path"

section "Raw Gin handler inventory by package"
raw_hits="$tmp_dir/raw-gin.txt"
api_rg 'func .*\*gin\.Context' > "$raw_hits" || true
raw_count="$(count_lines "$raw_hits")"
echo "raw gin function/method count: $raw_count"
if [[ "$raw_count" != "0" ]]; then
  awk -F: '
    {
      split($1, parts, "/")
      pkg = (parts[3] == "" || parts[3] ~ /\.go$/) ? "_root" : parts[3]
      count[pkg]++
    }
    END {
      for (pkg in count) printf "%5d %s\n", count[pkg], pkg
    }
  ' "$raw_hits" | sort -nr
fi

section "JSON bind inventory by package"
bind_hits="$tmp_dir/json-bind.txt"
api_rg '(ShouldBindJSON|BindJSON|\.Bind\()' > "$bind_hits" || true
bind_count="$(count_lines "$bind_hits")"
echo "json bind call count: $bind_count"
if [[ "$bind_count" != "0" ]]; then
  awk -F: '
    {
      split($1, parts, "/")
      pkg = (parts[3] == "" || parts[3] ~ /\.go$/) ? "_root" : parts[3]
      count[pkg]++
    }
    END {
      for (pkg in count) printf "%5d %s\n", count[pkg], pkg
    }
  ' "$bind_hits" | sort -nr
fi

section "Static route snapshot inputs"
route_hits="$tmp_dir/routes.txt"
api_rg '\.(GET|POST|PUT|PATCH|DELETE|OPTIONS|HEAD)\("' > "$route_hits" || true
route_count="$(count_lines "$route_hits")"
echo "static Gin route call count: $route_count"
if [[ "$route_count" != "0" ]]; then
  awk -F: '
    {
      split($1, parts, "/")
      pkg = (parts[3] == "" || parts[3] ~ /\.go$/) ? "_root" : parts[3]
      count[pkg]++
    }
    END {
      for (pkg in count) printf "%5d %s\n", count[pkg], pkg
    }
  ' "$route_hits" | sort -nr
fi

section "Adapter guardrails"
check_zero 'api.JSON helper usage' 'api\.JSON\('
check_zero 'old JSON wrapper type names' '\b(AuthenticatedJSONRequest|WorkspaceScopedJSONRequest)\b'
check_zero 'public optional JSON handler tier' '\b(AuthenticatedOptionalJSON|WorkspaceScopedOptionalJSON|HandleAuthOptionalJSON|HandleWorkspaceScopedOptionalJSON|BindOptionalJSON)\b'
check_zero 'anonymous gin.Context embed in typed request structs' '^[[:space:]]*\*gin\.Context'
check_zero 'custom typed request facade methods' 'func \([^)]*(AuthenticatedRequest|WorkspaceScopedRequest)[^)]*\) (Param|Query|Header|Bind|BindJSON|ShouldBindJSON)\('
check_zero 'old two-parameter JSON handler shape' 'func .*api\.(AuthenticatedRequest|WorkspaceScopedRequest),[[:space:]]*[A-Za-z_][A-Za-z0-9_]*[[:space:]]+dto\.[A-Za-z0-9_]+'
check_zero 'typed handler parameter named apiRequest' 'apiRequest api\.(AuthenticatedRequest|WorkspaceScopedRequest|AuthenticatedJSON\[|WorkspaceScopedJSON\[)'
check_zero 'typed handler manual Gin bind through r' '\br\.(Gin\.)?(ShouldBindJSON|Bind|BindJSON)\b'
check_zero 'old server/current-server adapter symbols' '\b(RequireCurrentServer|SetCurrentServer|CurrentServerFromContext|ServerRequest|HandleServer|HandleServerJSON|NewServerRequest)\b'

root_domain_import_hits="$tmp_dir/root-domain-imports.txt"
rg -n 'github\.com/tidbcloud/AgentTeam/internal/api/[^"/]+' internal/api/*.go > "$root_domain_import_hits" 2>/dev/null || true
root_domain_import_count="$(count_lines "$root_domain_import_hits")"
if [[ "$root_domain_import_count" != "0" ]]; then
  echo "FAIL: root internal/api imports API domain packages count=$root_domain_import_count"
  sed -n '1,40p' "$root_domain_import_hits"
  status=1
else
  echo "OK: root internal/api imports API domain packages count=0"
fi

helper_hits="$tmp_dir/helper-wrappers.txt"
helper_files=()
while IFS= read -r -d '' file; do
  helper_files+=("$file")
done < <(find internal/api -type f \( -name 'adapter_helpers.go' -o -name 'http_helpers.go' \) ! -path '*/testkit/*' -print0)
if (( ${#helper_files[@]} > 0 )); then
  rg -n 'api\.(HandleAuth|HandleWorkspaceScoped)|\bHandle(Auth|WorkspaceScoped)|\bhandle[A-Za-z]*(Auth|Workspace)' "${helper_files[@]}" > "$helper_hits" 2>/dev/null || true
else
  : > "$helper_hits"
fi
helper_count="$(count_lines "$helper_hits")"
if [[ "$helper_count" != "0" ]]; then
  echo "FAIL: helper-file adapter wrapper count=$helper_count"
  sed -n '1,40p' "$helper_hits"
  status=1
else
  echo "OK: helper-file adapter wrapper count=0"
fi

plan_hits="$tmp_dir/old-plan-ref.txt"
rg -n 'docs/refactor/api-handler-adapter-plan\.md|api-handler-adapter-plan\.md' . > "$plan_hits" || true
plan_count="$(count_lines "$plan_hits")"
if [[ "$plan_count" != "0" ]]; then
  echo "FAIL: old api-handler-adapter plan references count=$plan_count"
  sed -n '1,40p' "$plan_hits"
  status=1
else
  echo "OK: old api-handler-adapter plan references count=0"
fi

section "Oversized implementation files (>500 lines, non-test)"
oversized="$tmp_dir/oversized.txt"
while IFS= read -r -d '' file; do
  lines="$(wc -l < "$file" | tr -d '[:space:]')"
  if [[ "$lines" -gt 500 ]]; then
    printf '%5d %s\n' "$lines" "$file" >> "$oversized"
  fi
done < <(find internal/api -type f -name '*.go' ! -name '*_test.go' ! -path 'internal/api/testkit/*' -print0)
if [[ -s "$oversized" ]]; then
  sort -nr "$oversized" | head -30
else
  echo "none"
fi

section "High top-level function-count candidates (>20 funcs, non-test)"
funcs_file="$tmp_dir/funcs.txt"
while IFS= read -r -d '' file; do
  funcs="$(rg -c '^func ' "$file" 2>/dev/null || true)"
  funcs="${funcs:-0}"
  if [[ "$funcs" -gt 20 ]]; then
    printf '%5d %s\n' "$funcs" "$file" >> "$funcs_file"
  fi
done < <(find internal/api -type f -name '*.go' ! -name '*_test.go' ! -path 'internal/api/testkit/*' -print0)
if [[ -s "$funcs_file" ]]; then
  sort -nr "$funcs_file" | head -30
else
  echo "none"
fi

section "Result"
if [[ "$status" -ne 0 ]]; then
  echo "internal-api clean-code guardrail failed"
  exit "$status"
fi

echo "internal-api clean-code guardrail passed"
