#!/bin/sh
# Read-only recommendation-plan generator for manifest architecture audit.
# Usage: architecture.recommend.sh system|app APP_NAME [options]
set -u
MANIFEST=${ARCH_MANIFEST:-/home/intel145/websites/system/policies/architecture.manifest.json}
APPS_ROOT=${APPS_ROOT:-/home/intel145/websites/apps}
SYSTEM_ROOT=${SYSTEM_ROOT:-/home/intel145/websites/system}
MODE=${1:-}; APP=${2:-}; shift 2 2>/dev/null || true
DETAILS=0; MISSING_ONLY=0; BACKUP=0; OUTPUT=
usage(){ cat <<'EOF'
Usage:
  architecture.recommend.sh system [options]
  architecture.recommend.sh app APP_NAME [options]

Options:
  --manifest FILE   External architecture JSON manifest
  --details         Include evidence paths and rules
  --missing-only    Include only missing/forbidden/violation recommendations
  --backup          Include backup/editor-residue recommendations
  --output FILE     Write recommendation plan to FILE
  -h, --help        Show help

Creates a review-only Markdown recommendation plan. It never creates,
moves, renames, deletes, or changes permissions on any path.
EOF
}
case "$MODE" in system) [ -z "$APP" ] || :;; app) [ -n "$APP" ] || { echo 'ERROR: app mode requires APP_NAME.' >&2; exit 2; };; -h|--help|'') usage; exit 2;; *) echo 'ERROR: mode must be system or app.' >&2; exit 2;; esac
while [ "$#" -gt 0 ]; do case "$1" in --manifest) MANIFEST=$2; shift 2;; --details) DETAILS=1; shift;; --missing-only) MISSING_ONLY=1; shift;; --backup) BACKUP=1; shift;; --output) OUTPUT=$2; shift 2;; -h|--help) usage; exit 0;; *) echo "ERROR: unknown option: $1" >&2; exit 2;; esac; done
[ -f "$MANIFEST" ] || { echo "ERROR: manifest not found: $MANIFEST" >&2; exit 2; }; command -v python3 >/dev/null 2>&1 || { echo 'ERROR: python3 required.' >&2; exit 2; }
json(){ python3 - "$MANIFEST" "$@" <<'PY'
import json,sys
v=json.load(open(sys.argv[1]))
for k in sys.argv[2:]: v=v[k]
if isinstance(v,list): print('\n'.join(map(str,v)))
else: print(v)
PY
}
if [ "$MODE" = system ]; then ROOT=$SYSTEM_ROOT; SECTION=system; LABEL=system; else case "$APP" in *[!a-z0-9_]*|'') echo 'ERROR: invalid app name.' >&2; exit 2;; esac; ROOT=$APPS_ROOT/$APP; SECTION=application; LABEL="app:$APP"; fi
[ -d "$ROOT" ] || { echo "ERROR: target not found: $ROOT" >&2; exit 2; }; ROOT=$(cd "$ROOT" && pwd -P)
TMP=${TMPDIR:-/tmp}/architecture_recommend_$$; trap 'rm -f "$TMP".*' EXIT HUP INT TERM; : > "$TMP.md"; : > "$TMP.evidence"
add(){ printf '%s\n' "$1" >> "$TMP.md"; }
add '# Architecture Recommendation Plan'; add ''; add "- Target: \`$LABEL\`"; add "- Root: \`$ROOT\`"; add "- Manifest: \`$MANIFEST\`"; add '- Mode: read-only recommendation generation'; add ''; add '## Safety'; add ''; add 'This plan is a review artifact. It does not create directories, move files, rename files, delete files, alter permissions, or modify Nginx/server configuration.'; add ''
add '## Recommended actions'; add ''
for x in $(json "$SECTION" required_directories 2>/dev/null || true); do if [ ! -d "$ROOT/$x" ]; then add "- [ ] **Required directory missing:** create \`$x/\` only after confirming its declared purpose and owner."; [ "$DETAILS" -eq 1 ] && add "  - Rule: manifest \`$SECTION.required_directories\` requires \`$x/\`."; fi; done
for x in $(json "$SECTION" recommended_directories 2>/dev/null || true); do if [ ! -d "$ROOT/$x" ]; then add "- [ ] **Recommended directory absent:** consider creating \`$x/\` when its capability is adopted; it is not required today."; [ "$DETAILS" -eq 1 ] && add "  - Rule: manifest \`$SECTION.recommended_directories\` recommends \`$x/\`."; fi; done
for x in $(json "$SECTION" forbidden_directories 2>/dev/null || true); do if [ -e "$ROOT/$x" ]; then add "- [ ] **Forbidden directory exists:** review \`$x/\`; move its contents to an approved owner directory or change the manifest only after architecture review."; fi; done
if [ "$MODE" = app ]; then
 entries=$(json application required_any_entry_files | sed "s/{app}/$APP/g"); found=0; for e in $entries; do [ -f "$ROOT/$e" ] && found=1; done; if [ "$found" -eq 0 ]; then add '- [ ] **Entry point missing:** create or register one approved public entry file.'; [ "$DETAILS" -eq 1 ] && add "  - Expected one of: \`$(printf '%s' "$entries" | tr '\n' ' ')\`."; fi
fi
python3 - "$MANIFEST" "$ROOT" > "$TMP.naming" <<'PY'
import json,os,re,sys
m=json.load(open(sys.argv[1]));root=sys.argv[2];n=m['naming'];dr=re.compile(n['directory_name_regex']);fr=re.compile(n['file_base_name_regex']);exc=set(n.get('exception_directories',[]))
for b,ds,fs in os.walk(root):
 rel=os.path.relpath(b,root); parts=[] if rel=='.' else rel.split(os.sep); inherited=any(p in exc for p in parts)
 for x in ds:
  p=os.path.relpath(os.path.join(b,x),root)
  if not inherited and x not in exc and not dr.fullmatch(x): print('DIR|'+p)
 for x in fs:
  p=os.path.relpath(os.path.join(b,x),root); stem=x.rsplit('.',1)[0] if '.' in x else x
  if not inherited and not fr.fullmatch(stem): print('FILE|'+p)
PY
if [ -s "$TMP.naming" ]; then add '- [ ] **Naming migration inventory:** review the paths below; do not bulk-rename until all references are identified.'; if [ "$DETAILS" -eq 1 ]; then add '  - Rule: file/directory patterns are defined in the manifest.'; while IFS='|' read -r kind path; do add "  - \`$kind\`: \`$path\`"; done < "$TMP.naming"; fi; fi
if [ "$MODE" = app ]; then grep -RIl --include='*.php' -E 'class="[^"]*app-wrapper' "$ROOT" 2>/dev/null | grep -vE '/(old|test|tests|fixture|fixtures|example|examples|backup|moved|tmp)/' > "$TMP.wrap" || true; wc=$(wc -l < "$TMP.wrap" | tr -d ' '); max=$(json application component_rules max_active_app_wrapper_files); if [ "$wc" -gt "$max" ]; then add '- [ ] **Global layout ownership:** keep `.app-wrapper` in exactly one active primary template; remove it from active partials.'; [ "$DETAILS" -eq 1 ] && while IFS= read -r p; do add "  - Evidence: \`${p#$ROOT/}\`"; done < "$TMP.wrap"; fi; for f in $(json application component_rules fragment_directories); do [ -d "$ROOT/$f" ] || continue; grep -RIn --include='*.php' -E 'class="[^"]*(app-wrapper|app-main)' "$ROOT/$f" 2>/dev/null > "$TMP.$f" || true; if [ -s "$TMP.$f" ]; then add "- [ ] **Fragment layout violation:** remove global layout markup from \`$f/\`."; [ "$DETAILS" -eq 1 ] && while IFS= read -r line; do add "  - Evidence: \`${line#$ROOT/}\`"; done < "$TMP.$f"; fi; done; fi
if [ "$BACKUP" -eq 1 ]; then find "$ROOT" -type f \( -name '*.bak' -o -name '*.backup' -o -name '*~' -o -name '*.swp' \) -print > "$TMP.backups" 2>/dev/null || true; if [ -s "$TMP.backups" ]; then add '- [ ] **Backup/editor residue:** move retained copies outside the served root or delete after review.'; [ "$DETAILS" -eq 1 ] && while IFS= read -r p; do add "  - Evidence: \`${p#$ROOT/}\`"; done < "$TMP.backups"; fi; fi
add ''; add '## Manual deployment review'; add ''; add '- [ ] Confirm Nginx/hosting denies direct HTTP access to private application directories: `config/`, `docs/`, `includes/`, `pages/`, `src/`, `storage/`, `tests/`, `vendor/`, and `old/`.'; add '- [ ] Confirm public asset paths such as `css/`, `js/`, `images/`, and `assets/` remain accessible.'; add '- [ ] Re-run the manifest audit and naming audit after each reviewed change.'; add ''; add '## Deliberately not automated'; add ''; add '- No `mkdir`, `mv`, `rm`, `chmod`, deployment, server reload, or Nginx configuration changes are generated.'; add '- Renames require a separate reviewed rename plan because includes, URLs, imports, and deployment references can break.'
if [ -n "$OUTPUT" ]; then mkdir -p "$(dirname "$OUTPUT")"; cp "$TMP.md" "$OUTPUT"; echo "Recommendation plan written: $OUTPUT"; else cat "$TMP.md"; fi
