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

ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
cd "$ROOT"

failures=0

fail() {
  printf 'FAIL: %s\n' "$1" >&2
  failures=$((failures + 1))
}

is_kebab() {
  [[ "$1" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]
}

check_shell_guardrail() {
  local path="$1"
  local first second
  first=$(sed -n '1p' "$path")
  second=$(sed -n '2p' "$path")
  [[ "$first" == '#!/usr/bin/env bash' ]] || fail "$path must start with #!/usr/bin/env bash"
  [[ "$second" == 'set -euo pipefail' ]] || fail "$path must set -euo pipefail on line 2"
  [[ -x "$path" ]] || fail "$path must be executable"
}

check_python_guardrail() {
  local path="$1"
  local first
  first=$(sed -n '1p' "$path")
  [[ "$first" == '#!/usr/bin/env python3' ]] || fail "$path must start with #!/usr/bin/env python3"
  [[ -x "$path" ]] || fail "$path must be executable"
}

if [[ -d docs/specs ]]; then
  while IFS= read -r legacy_spec; do
    fail "legacy canonical spec remains: $legacy_spec"
  done < <(find docs/specs -type f -name '*.md' | sort)
fi

[[ -f SPECS.md ]] || fail "root SPECS.md must exist as the top-level specs index"
[[ ! -f specs/README.md ]] || fail "root specs/README.md must not become a second top-level specs index"
[[ ! -f docs/product_spec.md ]] || fail "legacy product spec entry remains: docs/product_spec.md"
[[ ! -f docs/spec.md ]] || fail "legacy spec alias remains: docs/spec.md"

while IFS= read -r legacy_index; do
  fail "domain index must be README.md, not INDEX.md: $legacy_index"
done < <(find specs guardrails -mindepth 2 -maxdepth 2 -name 'INDEX.md' 2>/dev/null | sort)

while IFS= read -r ref; do
  fail "legacy spec entry reference remains: $ref"
done < <(
  git grep -n -E 'docs/specs|docs/product_spec\.md|product_spec\.md|docs/spec\.md' -- \
    ':(exclude)guardrails/repository/specs-and-guardrails-layout.sh' \
    ':(exclude).git' \
    ':(exclude)web/dist' \
    ':(exclude)webassets/dist' || true
)

while IFS= read -r domain_dir; do
  index="$domain_dir/README.md"
  [[ -f "$index" ]] || fail "$domain_dir must contain README.md"
done < <(find specs -mindepth 1 -maxdepth 1 -type d | sort)

while IFS= read -r spec; do
  rel=${spec#specs/}
  IFS='/' read -r -a parts <<< "$rel"
  if (( ${#parts[@]} < 2 )); then
    fail "$spec must be under specs/{domain}/"
    continue
  fi
  domain=${parts[0]}
  is_kebab "$domain" || fail "$spec domain must be kebab-case: $domain"

  filename=${parts[$((${#parts[@]} - 1))]}
  basename=${filename%.md}
  is_kebab "$basename" || fail "$spec filename must be kebab-case: $filename"
  [[ "$filename" == *.md ]] || fail "$spec must use .md"

  if (( ${#parts[@]} == 2 )); then
    :
  elif (( ${#parts[@]} == 3 )); then
    subdomain=${parts[1]}
    is_kebab "$subdomain" || fail "$spec subdomain must be kebab-case: $subdomain"
  elif (( ${#parts[@]} >= 4 )); then
    if [[ "${parts[1]}" == assets && "${parts[2]}" == media ]]; then
      :
    elif (( ${#parts[@]} >= 5 )) && [[ "${parts[2]}" == assets && "${parts[3]}" == media ]]; then
      subdomain=${parts[1]}
      is_kebab "$subdomain" || fail "$spec subdomain must be kebab-case: $subdomain"
    else
      fail "$spec exceeds specs/{domain}/{subdomain}/{spec-name}.md depth"
    fi
  fi

  canonical=$(grep -E -m1 '^[[:space:]>-]*(Canonical path|规范路径):[[:space:]]*`?[^`]+`?' "$spec" || true)
  if [[ -n "$canonical" ]]; then
    declared=$(printf '%s\n' "$canonical" | sed -E 's/.*(Canonical path|规范路径):[[:space:]]*`?([^`[:space:]]+).*/\2/')
    [[ "$declared" == "$spec" ]] || fail "$spec canonical path declares $declared"
  fi
done < <(find specs -type f -name '*.md' ! -name 'README.md' | sort)

while IFS= read -r domain_dir; do
  index="$domain_dir/README.md"
  [[ -f "$index" ]] || fail "$domain_dir must contain README.md"
done < <(find guardrails -mindepth 1 -maxdepth 1 -type d | sort)

while IFS= read -r guardrail; do
  rel=${guardrail#guardrails/}
  IFS='/' read -r -a parts <<< "$rel"
  if (( ${#parts[@]} < 2 )); then
    fail "$guardrail must be under guardrails/{domain}/"
    continue
  fi
  domain=${parts[0]}
  is_kebab "$domain" || fail "$guardrail domain must be kebab-case: $domain"
  [[ -d "specs/$domain" ]] || fail "$guardrail has no matching specs domain: specs/$domain"

  filename=${parts[$((${#parts[@]} - 1))]}
  basename=${filename%.*}
  is_kebab "$basename" || fail "$guardrail filename must be kebab-case: $filename"
  case "$filename" in
    *.sh) check_shell_guardrail "$guardrail" ;;
    *.py) check_python_guardrail "$guardrail" ;;
    *) fail "$guardrail must use .sh or .py" ;;
  esac

  if (( ${#parts[@]} == 3 )); then
    subdomain=${parts[1]}
    is_kebab "$subdomain" || fail "$guardrail subdomain must be kebab-case: $subdomain"
    [[ -d "specs/$domain/$subdomain" ]] || fail "$guardrail has no matching specs subdomain: specs/$domain/$subdomain"
  elif (( ${#parts[@]} > 3 )); then
    fail "$guardrail exceeds guardrails/{domain}/{subdomain}/{script-name}.sh depth"
  fi

done < <(find guardrails -type f \( -name '*.sh' -o -name '*.py' \) | sort)

if (( failures > 0 )); then
  printf '\nSpecs/guardrails layout check failed with %d issue(s).\n' "$failures" >&2
  exit 1
fi

printf 'Specs/guardrails layout check passed.\n'
