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

PROJECT_DIR=""
OUTPUT_DIR=""

usage() {
  cat <<'EOF'
Create a complete, clean, share-safe Laravel source archive.

Usage:
  ./backup-source-clean-v2.sh [options]

Options:
  --project PATH     Laravel project path
  --output PATH      Directory for the generated archive
  -h, --help         Show this help

Defaults:
  Project: current directory when it contains artisan, otherwise
           /home/snyt/public_html/SubDomain/Catalog
  Output:  project directory

The archive includes the complete Laravel source structure while excluding
dependencies, runtime caches, uploads, databases, logs, secrets, old snapshots,
and previously generated archives.
EOF
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --project)
      [[ $# -ge 2 ]] || { echo "ERROR: --project requires a path." >&2; exit 1; }
      PROJECT_DIR="$2"
      shift 2
      ;;
    --output)
      [[ $# -ge 2 ]] || { echo "ERROR: --output requires a path." >&2; exit 1; }
      OUTPUT_DIR="$2"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "ERROR: Unknown option: $1" >&2
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$PROJECT_DIR" ]]; then
  if [[ -f "$(pwd)/artisan" ]]; then
    PROJECT_DIR="$(pwd)"
  else
    PROJECT_DIR="/home/snyt/public_html/SubDomain/Catalog"
  fi
fi

PROJECT_DIR="${PROJECT_DIR/#\~/$HOME}"
PROJECT_DIR="$(cd "$PROJECT_DIR" 2>/dev/null && pwd)" || {
  echo "ERROR: Project directory not found: $PROJECT_DIR" >&2
  exit 1
}

if [[ ! -f "$PROJECT_DIR/artisan" || ! -f "$PROJECT_DIR/composer.json" ]]; then
  echo "ERROR: This does not look like a Laravel project:" >&2
  echo "$PROJECT_DIR" >&2
  exit 1
fi

if [[ -z "$OUTPUT_DIR" ]]; then
  OUTPUT_DIR="$PROJECT_DIR"
fi

OUTPUT_DIR="${OUTPUT_DIR/#\~/$HOME}"
mkdir -p "$OUTPUT_DIR"
OUTPUT_DIR="$(cd "$OUTPUT_DIR" && pwd)"

command -v rsync >/dev/null 2>&1 || {
  echo "ERROR: rsync is required." >&2
  exit 1
}

command -v tar >/dev/null 2>&1 || {
  echo "ERROR: tar is required." >&2
  exit 1
}

DATE="$(date '+%Y-%m-%d_%H-%M-%S')"
ARCHIVE_NAME="catalog-source-clean-${DATE}.tar.gz"
OUTPUT_FILE="$OUTPUT_DIR/$ARCHIVE_NAME"

TEMP_DIR="$(mktemp -d)"
STAGE_NAME="Catalog"
STAGE_DIR="$TEMP_DIR/$STAGE_NAME"

cleanup() {
  rm -rf "$TEMP_DIR"
}
trap cleanup EXIT

mkdir -p "$STAGE_DIR"

echo
echo "=================================================="
echo " SNYT CLEAN LARAVEL SOURCE BACKUP"
echo "=================================================="
echo "Project: $PROJECT_DIR"
echo "Output:  $OUTPUT_FILE"
echo

rsync -a \
  --include='/.env.example' \
  --exclude='/.env' \
  --exclude='/.env.*' \
  --exclude='/.git/' \
  --exclude='/.idea/' \
  --exclude='/.vscode/' \
  --exclude='/vendor/' \
  --exclude='/node_modules/' \
  --exclude='/storage/app/***' \
  --exclude='/storage/framework/***' \
  --exclude='/storage/logs/***' \
  --exclude='/bootstrap/cache/*.php' \
  --exclude='/public/storage' \
  --exclude='/public/hot' \
  --exclude='/public/build/***' \
  --exclude='/database/*.sqlite*' \
  --exclude='*.before-*' \
  --exclude='*.bak-*' \
  --exclude='*.bak' \
  --exclude='*.backup' \
  --exclude='*.old' \
  --exclude='*.orig' \
  --exclude='*.disabled' \
  --exclude='*~' \
  --exclude='*.log' \
  --exclude='*.tmp' \
  --exclude='*.temp' \
  --exclude='*.swp' \
  --exclude='*.swo' \
  --exclude='*.tar' \
  --exclude='*.tar.gz' \
  --exclude='*.tgz' \
  --exclude='*.zip' \
  --exclude='*.rar' \
  --exclude='*.7z' \
  --exclude='*.sql' \
  --exclude='*.dump' \
  --exclude='*.pem' \
  --exclude='*.key' \
  --exclude='*.p12' \
  --exclude='*.pfx' \
  --exclude='*.crt' \
  --exclude='*.cer' \
  --exclude='auth.json' \
  --exclude='.npmrc' \
  --exclude='credentials.json' \
  --exclude='/error_log' \
  --exclude='/test.txt' \
  --exclude='/backUp.sh' \
  --exclude='/scripts/backup-source.sh' \
  --exclude='.DS_Store' \
  --exclude='Thumbs.db' \
  "$PROJECT_DIR/" "$STAGE_DIR/"

# Recreate Laravel runtime directories without copying runtime/customer data.
mkdir -p \
  "$STAGE_DIR/bootstrap/cache" \
  "$STAGE_DIR/storage/app/private" \
  "$STAGE_DIR/storage/app/public" \
  "$STAGE_DIR/storage/framework/cache/data" \
  "$STAGE_DIR/storage/framework/sessions" \
  "$STAGE_DIR/storage/framework/views" \
  "$STAGE_DIR/storage/logs"

for rel in \
  bootstrap/cache/.gitignore \
  storage/app/.gitignore \
  storage/app/private/.gitignore \
  storage/app/public/.gitignore \
  storage/framework/.gitignore \
  storage/framework/cache/.gitignore \
  storage/framework/cache/data/.gitignore \
  storage/framework/sessions/.gitignore \
  storage/framework/views/.gitignore \
  storage/logs/.gitignore
do
  if [[ -f "$PROJECT_DIR/$rel" ]]; then
    mkdir -p "$(dirname "$STAGE_DIR/$rel")"
    cp "$PROJECT_DIR/$rel" "$STAGE_DIR/$rel"
  fi
done

REQUIRED_FILES=(
  artisan
  composer.json
  composer.lock
  bootstrap/app.php
  public/index.php
  config/app.php
  routes/web.php
)

MISSING=0
for rel in "${REQUIRED_FILES[@]}"; do
  if [[ ! -f "$STAGE_DIR/$rel" ]]; then
    echo "ERROR: Required source file is missing: $rel" >&2
    MISSING=$((MISSING + 1))
  fi
done

if [[ $MISSING -ne 0 ]]; then
  echo
  echo "Archive creation stopped because the project source is incomplete." >&2
  exit 2
fi

if [[ ! -f "$STAGE_DIR/.env.example" ]]; then
  echo "WARNING: .env.example is missing from the project."
fi

SENSITIVE_FOUND=0

while IFS= read -r -d '' file; do
  echo "ERROR: Sensitive file entered the staging directory: ${file#"$STAGE_DIR"/}" >&2
  SENSITIVE_FOUND=1
done < <(
  find "$STAGE_DIR" -type f \
    \( \
      -name '.env' -o \
      \( -name '.env.*' ! -name '.env.example' \) -o \
      -name '*.pem' -o \
      -name '*.key' -o \
      -name '*.p12' -o \
      -name '*.pfx' -o \
      -name 'auth.json' -o \
      -name '.npmrc' -o \
      -name 'credentials.json' \
    \) \
    -print0
)

if grep -RIl --binary-files=without-match \
  -E '-----BEGIN ([A-Z0-9 ]+ )?PRIVATE KEY-----' \
  "$STAGE_DIR" >/tmp/snyt_private_key_hits.$$ 2>/dev/null
then
  while IFS= read -r file; do
    [[ -n "$file" ]] || continue
    echo "ERROR: Private-key content detected in: ${file#"$STAGE_DIR"/}" >&2
    SENSITIVE_FOUND=1
  done < /tmp/snyt_private_key_hits.$$
fi
rm -f /tmp/snyt_private_key_hits.$$

if [[ $SENSITIVE_FOUND -ne 0 ]]; then
  echo "Archive creation stopped for safety." >&2
  exit 3
fi

mkdir -p "$STAGE_DIR/_project_review"

{
  echo "SNYT Catalog clean Laravel source archive"
  echo "Created: $(date)"
  echo "Original project: $PROJECT_DIR"
  echo
  echo "Included:"
  echo "- Complete Laravel application source"
  echo "- bootstrap, public entry point, routes, config, database migrations"
  echo "- Composer/NPM manifests and lock files when present"
  echo "- tests, documentation, scripts, and static source assets"
  echo
  echo "Excluded:"
  echo "- .env and credential files"
  echo "- vendor and node_modules"
  echo "- runtime caches, sessions, logs, uploads, generated catalogs"
  echo "- SQLite databases and SQL dumps"
  echo "- .before-*, .bak-* and other local snapshots"
  echo "- generated archives and compiled Vite output"
} > "$STAGE_DIR/_project_review/ARCHIVE_INFO.txt"

find "$STAGE_DIR" -type f \
  | sed "s|$STAGE_DIR/||" \
  | sort \
  > "$STAGE_DIR/_project_review/INCLUDED_FILES.txt"

rm -f "$OUTPUT_FILE"
tar -czf "$OUTPUT_FILE" -C "$TEMP_DIR" "$STAGE_NAME"

if command -v sha256sum >/dev/null 2>&1; then
  sha256sum "$OUTPUT_FILE" > "${OUTPUT_FILE}.sha256"
elif command -v shasum >/dev/null 2>&1; then
  shasum -a 256 "$OUTPUT_FILE" > "${OUTPUT_FILE}.sha256"
fi

echo
echo "Backup completed:"
echo "$OUTPUT_FILE"
du -h "$OUTPUT_FILE"

if [[ -f "${OUTPUT_FILE}.sha256" ]]; then
  echo
  echo "Checksum:"
  cat "${OUTPUT_FILE}.sha256"
fi
