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

VERSION="0.2.0"
PROJECT_DIR="${1:-.}"
OUTPUT_FILE="${2:-shipsentry-report.md}"
REPORT_BASENAME="$(basename "$OUTPUT_FILE")"

if [[ ! -d "$PROJECT_DIR" ]]; then
  printf 'ShipSentry: project directory not found: %s\n' "$PROJECT_DIR" >&2
  exit 2
fi

PROJECT_DIR="$(cd "$PROJECT_DIR" && pwd)"

if [[ ! -f "$PROJECT_DIR/settings.gradle" && ! -f "$PROJECT_DIR/settings.gradle.kts" ]]; then
  printf 'ShipSentry: %s does not look like a Gradle project.\n' "$PROJECT_DIR" >&2
  exit 2
fi

declare -a FINDING_SEVERITY=()
declare -a FINDING_TITLE=()
declare -a FINDING_EVIDENCE=()
declare -a FINDING_FIX=()

add_finding() {
  FINDING_SEVERITY+=("$1")
  FINDING_TITLE+=("$2")
  FINDING_EVIDENCE+=("$3")
  FINDING_FIX+=("$4")
}

search_project() {
  local pattern="$1"
  shift
  grep -RInE \
    --exclude-dir=.git \
    --exclude-dir=.gradle \
    --exclude-dir=build \
    --exclude-dir=.idea \
    --exclude="$REPORT_BASENAME" \
    --exclude='*.png' \
    --exclude='*.jpg' \
    --exclude='*.jpeg' \
    --exclude='*.webp' \
    "$pattern" "$PROJECT_DIR" "$@" 2>/dev/null | head -n 5 || true
}

relative_evidence() {
  sed "s#${PROJECT_DIR}/##g" | sed 's/|/\\|/g'
}

record_matches() {
  local severity="$1"
  local title="$2"
  local pattern="$3"
  local fix="$4"
  local matches
  matches="$(search_project "$pattern" | relative_evidence)"
  if [[ -n "$matches" ]]; then
    add_finding "$severity" "$title" "$matches" "$fix"
  fi
}

record_matches "HIGH" "Release build may be debuggable" \
  '(debuggable|isDebuggable)[[:space:]]*(=| )[[:space:]]*true' \
  'Remove `debuggable true` from release variants and verify the merged release manifest.'

record_matches "HIGH" "Cleartext network traffic is enabled" \
  'usesCleartextTraffic[[:space:]]*=[[:space:]]*"true"|cleartextTrafficPermitted[[:space:]]*=[[:space:]]*"true"' \
  'Disable cleartext globally. If an exception is unavoidable, scope it to the exact development host.'

record_matches "HIGH" "Potential credential committed to source" \
  '(api[_-]?key|secret|access[_-]?token|client[_-]?secret)[[:space:]]*[:=][[:space:]]*"[A-Za-z0-9_./+=-]{16,}' \
  'Revoke exposed credentials, remove them from Git history, and inject replacements through CI secrets.'

record_matches "HIGH" "Signing material may be stored in the repository" \
  '(storePassword|keyPassword)[[:space:]]*[:=][[:space:]]*"[^"]+"' \
  'Move signing values to an untracked local properties file or CI secret store, then rotate the credentials.'

record_matches "MEDIUM" "Application backup is explicitly enabled" \
  'android:allowBackup[[:space:]]*=[[:space:]]*"true"' \
  'Set an explicit backup policy and exclude tokens, identifiers, and other sensitive files.'

record_matches "MEDIUM" "WebView exposes a JavaScript bridge" \
  'addJavascriptInterface[[:space:]]*\(' \
  'Only expose a minimal annotated interface to trusted content, validate navigation, and avoid loading untrusted pages.'

record_matches "MEDIUM" "WebView permits file access" \
  '(allowFileAccess|setAllowFileAccess)[[:space:]]*(=|\()[[:space:]]*true' \
  'Disable file access unless it is required and tightly constrain any content loaded into the WebView.'

record_matches "MEDIUM" "Release shrinking appears disabled" \
  '(minifyEnabled|isMinifyEnabled)[[:space:]]*(=| )[[:space:]]*false' \
  'Enable R8 for release builds, add focused keep rules, and exercise critical flows in a release-like test build.'

record_matches "LOW" "Development logging remains in source" \
  'Log\.(v|d|i|w|e)[[:space:]]*\(|println[[:space:]]*\(' \
  'Route logs through a release-aware logger and ensure sensitive values are never emitted.'

record_matches "LOW" "Release follow-up markers remain" \
  '(TODO|FIXME)[(: ]' \
  'Review each marker before release and convert accepted debt into tracked work items.'

high_count=0
medium_count=0
low_count=0
for severity in "${FINDING_SEVERITY[@]-}"; do
  case "$severity" in
    HIGH) high_count=$((high_count + 1)) ;;
    MEDIUM) medium_count=$((medium_count + 1)) ;;
    LOW) low_count=$((low_count + 1)) ;;
  esac
done

generated_at="$(date -u '+%Y-%m-%d %H:%M UTC')"

{
  printf '# ShipSentry Lite Report\n\n'
  printf '> Generated by ShipSentry Lite v%s on %s. Static analysis only; findings require human verification.\n\n' "$VERSION" "$generated_at"
  printf '## Summary\n\n'
  printf '| High | Medium | Low | Total |\n'
  printf '|---:|---:|---:|---:|\n'
  printf '| %d | %d | %d | %d |\n\n' "$high_count" "$medium_count" "$low_count" "${#FINDING_TITLE[@]}"

  if [[ ${#FINDING_TITLE[@]} -eq 0 ]]; then
    printf 'No patterns were flagged. This does not prove the application is release-ready.\n\n'
  else
    printf '## Findings\n\n'
    for index in "${!FINDING_TITLE[@]}"; do
      printf '### %d. [%s] %s\n\n' "$((index + 1))" "${FINDING_SEVERITY[$index]}" "${FINDING_TITLE[$index]}"
      printf '**Evidence**\n\n```text\n%s\n```\n\n' "${FINDING_EVIDENCE[$index]}"
      printf '**Recommended fix:** %s\n\n' "${FINDING_FIX[$index]}"
    done
  fi

  printf '## Coverage\n\n'
  printf 'This Lite scan checks common release configuration, secret exposure, network security, WebView, logging, and code-marker patterns. It does not inspect runtime behavior, dependency CVEs, merged manifests, Play policy declarations, or R8 reachability.\n'
} > "$OUTPUT_FILE"

printf 'ShipSentry: wrote %s (%d high, %d medium, %d low)\n' "$OUTPUT_FILE" "$high_count" "$medium_count" "$low_count"
