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

usage() {
  cat <<'USAGE'
Usage:
  zielwerk inspect meow
  zielwerk inspect --json meow
  zielwerk validate-target meow
  zielwerk validate-target meow --inspect-json <file>
  ZIELWERK_INSPECT_LOCAL=1 zielwerk inspect meow

Zielwerk bootstrap recipe CLI.
Provides target inspection without exposing environment values, credentials, or
secret references.
USAGE
}

die() {
  printf 'zielwerk: %s\n' "$*" >&2
  exit 1
}

redact_line() {
  sed -E \
    -e 's/(token|secret|password|passwd|credential|private[_-]?key|client[_-]?secret|bearer)[^[:space:]]*/[REDACTED]/Ig' \
    -e 's#tresor://[^[:space:]]+#[REDACTED-SECRET-REF]#Ig' \
    -e 's#[A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE_KEY|CREDENTIAL)[A-Za-z0-9_]*#[REDACTED-ENV-NAME]#g'
}

contains_secret_marker() {
  grep -Eiq '(tresor://|Bearer[[:space:]]+[A-Za-z0-9._-]+|[A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE_KEY|CREDENTIAL)[A-Za-z0-9_]*=|client_secret[[:space:]]*:[[:space:]]*"[^"]+|private[_-]?key[[:space:]]*:[[:space:]]*"[^"]+)'
}

require_file_contains() {
  local file="$1"
  local pattern="$2"
  local message="$3"

  if grep -Eq "$pattern" "$file"; then
    printf 'ok: %s\n' "$message"
  else
    printf 'error: %s\n' "$message" >&2
    return 1
  fi
}

inspect_payload() {
  cat <<'REMOTE'
set -eu

redact_line() {
  sed -E \
    -e 's/(token|secret|password|passwd|credential|private[_-]?key|client[_-]?secret|bearer)[^[:space:]]*/[REDACTED]/Ig' \
    -e 's#tresor://[^[:space:]]+#[REDACTED-SECRET-REF]#Ig' \
    -e 's#[A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE_KEY|CREDENTIAL)[A-Za-z0-9_]*#[REDACTED-ENV-NAME]#g'
}

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

json_string() {
  printf '%s' "$1" | sed \
    -e 's/\\/\\\\/g' \
    -e 's/"/\\"/g' \
    -e 's/	/\\t/g'
}

optional() {
  label="$1"
  output=""
  shift
  section "$label"
  if output="$("$@" 2>/dev/null)"; then
    if [ -n "$output" ]; then
      printf '%s\n' "$output" | redact_line
    else
      printf 'status=empty\n'
    fi
  else
    printf 'status=unavailable\n'
  fi
}

json_array_from_lines() {
  first=1
  while IFS= read -r line; do
    if [ -n "$line" ]; then
      if [ "$first" -eq 0 ]; then
        printf ','
      fi
      printf '"%s"' "$(json_string "$line")"
      first=0
    fi
  done
}

json_command_array() {
  if output="$("$@" 2>/dev/null | redact_line)"; then
    printf '['
    if [ -n "$output" ]; then
      printf '%s\n' "$output" | json_array_from_lines
    fi
    printf ']'
  else
    printf '[]'
  fi
}

section target
printf 'id=meow\n'
printf 'generated_by=zielwerk.inspect\n'
printf 'secret_values_allowed=false\n'

section host
printf 'hostname=%s\n' "$(hostname 2>/dev/null || printf unknown)"
printf 'kernel=%s\n' "$(uname -s 2>/dev/null || printf unknown)"
printf 'architecture=%s\n' "$(uname -m 2>/dev/null || printf unknown)"

optional docker-version docker --version
optional docker-containers sh -c 'docker ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'
optional podman-root-version sudo -n podman --version
optional podman-root-containers sh -c 'sudo -n podman ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'
optional podman-user-version podman --version
optional podman-user-containers sh -c 'podman ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'
optional systemd-running sh -c 'systemctl list-units --type=service --state=running --no-legend --plain | awk "{print \"unit=\" \$1 \" state=\" \$3 \" desc=\" substr(\$0, index(\$0,\$5))}"'
optional systemd-user-running sh -c 'systemctl --user list-units --type=service --state=running --no-legend --plain | awk "{print \"unit=\" \$1 \" state=\" \$3 \" desc=\" substr(\$0, index(\$0,\$5))}"'
optional listening-ports sh -c 'ss -ltnp | awk "NR == 1 {next} {print}"'
optional manual-processes sh -c 'ps -eo pid=,ppid=,comm=,args= | awk "$2 == 1 {print}"'

section likely-data-paths
for path in /srv /opt /var/lib /var/local "$HOME/.local/share"; do
  if [ -d "$path" ]; then
    printf 'path=%s\n' "$path"
  fi
done

section likely-config-sources
for path in /etc/systemd/system "$HOME/.config/systemd/user" "$HOME/.config/containers" /etc/containers /etc/nginx /etc/caddy; do
  if [ -d "$path" ]; then
    printf 'path=%s\n' "$path"
  fi
done

section likely-health-urls
for port in 8080 8443 9470 9471 9711; do
  printf 'url=http://127.0.0.1:%s/health status=unchecked\n' "$port"
done
REMOTE
}

inspect_json_payload() {
  cat <<'REMOTE'
set -eu

redact_line() {
  sed -E \
    -e 's/(token|secret|password|passwd|credential|private[_-]?key|client[_-]?secret|bearer)[^[:space:]]*/[REDACTED]/Ig' \
    -e 's#tresor://[^[:space:]]+#[REDACTED-SECRET-REF]#Ig' \
    -e 's#[A-Za-z_][A-Za-z0-9_]*(TOKEN|SECRET|PASSWORD|PASSWD|PRIVATE_KEY|CREDENTIAL)[A-Za-z0-9_]*#[REDACTED-ENV-NAME]#g'
}

json_string() {
  printf '%s' "$1" | sed \
    -e 's/\\/\\\\/g' \
    -e 's/"/\\"/g' \
    -e 's/	/\\t/g'
}

json_array_from_lines() {
  first=1
  while IFS= read -r line; do
    if [ -n "$line" ]; then
      if [ "$first" -eq 0 ]; then
        printf ','
      fi
      printf '"%s"' "$(json_string "$line")"
      first=0
    fi
  done
}

json_command_array() {
  if output="$("$@" 2>/dev/null | redact_line)"; then
    printf '['
    if [ -n "$output" ]; then
      printf '%s\n' "$output" | json_array_from_lines
    fi
    printf ']'
  else
    printf '[]'
  fi
}

json_paths_array() {
  first=1
  for path in "$@"; do
    if [ -d "$path" ]; then
      if [ "$first" -eq 0 ]; then
        printf ','
      fi
      printf '"%s"' "$(json_string "$path")"
      first=0
    fi
  done
}

hostname_value="$(hostname 2>/dev/null || printf unknown)"
kernel_value="$(uname -s 2>/dev/null || printf unknown)"
architecture_value="$(uname -m 2>/dev/null || printf unknown)"

printf '{\n'
printf '  "schema": "zielwerk.inspect/v1",\n'
printf '  "target": "meow",\n'
printf '  "generated_by": "zielwerk.inspect",\n'
printf '  "redaction": {"enabled": true, "secret_values_allowed": false},\n'
printf '  "host": {"hostname": "%s", "kernel": "%s", "architecture": "%s"},\n' \
  "$(json_string "$hostname_value")" "$(json_string "$kernel_value")" "$(json_string "$architecture_value")"
printf '  "runtimes": {\n'
printf '    "docker_version": '; json_command_array docker --version; printf ',\n'
printf '    "docker_containers": '; json_command_array sh -c 'docker ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'; printf ',\n'
printf '    "podman_root_version": '; json_command_array sudo -n podman --version; printf ',\n'
printf '    "podman_root_containers": '; json_command_array sh -c 'sudo -n podman ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'; printf ',\n'
printf '    "podman_user_version": '; json_command_array podman --version; printf ',\n'
printf '    "podman_user_containers": '; json_command_array sh -c 'podman ps --format "container={{.Names}} image={{.Image}} ports={{.Ports}} status={{.Status}}"'; printf '\n'
printf '  },\n'
printf '  "systemd": {\n'
printf '    "root_running": '; json_command_array sh -c 'systemctl list-units --type=service --state=running --no-legend --plain | awk "{print \"unit=\" \$1 \" state=\" \$3 \" desc=\" substr(\$0, index(\$0,\$5))}"'; printf ',\n'
printf '    "user_running": '; json_command_array sh -c 'systemctl --user list-units --type=service --state=running --no-legend --plain | awk "{print \"unit=\" \$1 \" state=\" \$3 \" desc=\" substr(\$0, index(\$0,\$5))}"'; printf '\n'
printf '  },\n'
printf '  "network": {"listening_ports": '; json_command_array sh -c 'ss -ltnp | awk "NR == 1 {next} {print}"'; printf '},\n'
printf '  "manual_processes": '; json_command_array sh -c 'ps -eo pid=,ppid=,comm=,args= | awk "$2 == 1 {print}"'; printf ',\n'
printf '  "data_paths": ['; json_paths_array /srv /opt /var/lib /var/local "$HOME/.local/share"; printf '],\n'
printf '  "config_sources": ['; json_paths_array /etc/systemd/system "$HOME/.config/systemd/user" "$HOME/.config/containers" /etc/containers /etc/nginx /etc/caddy; printf '],\n'
printf '  "health_urls": ["http://127.0.0.1:8080/health", "http://127.0.0.1:8443/health", "http://127.0.0.1:9470/health", "http://127.0.0.1:9471/health", "http://127.0.0.1:9711/health"]\n'
printf '}\n'
REMOTE
}

run_remote_payload() {
  local payload="$1"

  if [[ "${ZIELWERK_INSPECT_LOCAL:-0}" == "1" ]]; then
    bash -s < <("$payload")
    return 0
  fi

  ssh "${ZIELWERK_SSH_HOST:-meow}" 'bash -s' < <("$payload")
}

inspect_meow_text() {
  printf '# Zielwerk target inspect\n'
  printf '# target=meow\n'
  printf '# redaction=enabled\n'

  run_remote_payload inspect_payload
}

inspect_meow_json() {
  run_remote_payload inspect_json_payload
}

validate_target() {
  local target="$1"
  local inspect_json="${2:-}"
  local target_file=".werk/targets/${target}.akte.toml"
  local failures=0

  [[ "$target" == "meow" ]] || die "unknown target '$target'"
  [[ -f "$target_file" ]] || die "target Akte not found: $target_file"

  require_file_contains "$target_file" '^id = "target\.meow"$' "target Akte id is target.meow" || failures=$((failures + 1))
  require_file_contains "$target_file" '^kind = "target"$' "target Akte kind is target" || failures=$((failures + 1))
  require_file_contains "$target_file" '^host = "meow"$' "target host is meow" || failures=$((failures + 1))
  require_file_contains "$target_file" '^service_status_owner = "servicewerk"$' "service status owner stays Servicewerk" || failures=$((failures + 1))
  require_file_contains "$target_file" '^secret_owner = "tresor"$' "secret owner stays Tresor" || failures=$((failures + 1))
  require_file_contains "$target_file" '^authz_owner = "regelwerk"$' "authz owner stays Regelwerk" || failures=$((failures + 1))
  require_file_contains "$target_file" '^identity_owner = "keycloak"$' "identity owner stays Keycloak" || failures=$((failures + 1))
  require_file_contains "$target_file" '^secret_values_allowed = false$' "secret values are forbidden in target metadata" || failures=$((failures + 1))
  require_file_contains "$target_file" '^secret_refs_browser_safe = false$' "secret refs are not browser-safe" || failures=$((failures + 1))
  require_file_contains "$target_file" '^prod_swap_requires_explicit_plan = true$' "production swap requires explicit plan" || failures=$((failures + 1))
  require_file_contains "$target_file" 'allowed_runtime_states = \["docker", "podman-root", "podman-user", "systemd", "manual-process"\]' "mixed runtime states are declared" || failures=$((failures + 1))

  if [[ -n "$inspect_json" ]]; then
    [[ -f "$inspect_json" ]] || die "inspect JSON not found: $inspect_json"
    if command -v jq >/dev/null 2>&1; then
      if jq -e . "$inspect_json" >/dev/null; then
        printf 'ok: inspect JSON parses\n'
      else
        printf 'error: inspect JSON does not parse\n' >&2
        failures=$((failures + 1))
      fi
    fi
    require_file_contains "$inspect_json" '"schema"[[:space:]]*:[[:space:]]*"zielwerk\.inspect/v1"' "inspect JSON schema is zielwerk.inspect/v1" || failures=$((failures + 1))
    require_file_contains "$inspect_json" '"target"[[:space:]]*:[[:space:]]*"meow"' "inspect JSON target is meow" || failures=$((failures + 1))
    require_file_contains "$inspect_json" '"secret_values_allowed"[[:space:]]*:[[:space:]]*false' "inspect JSON forbids secret values" || failures=$((failures + 1))
    require_file_contains "$inspect_json" '"architecture"[[:space:]]*:[[:space:]]*"[^"]+"' "inspect JSON includes architecture" || failures=$((failures + 1))
    if contains_secret_marker < "$inspect_json"; then
      printf 'error: inspect JSON contains unredacted secret marker\n' >&2
      failures=$((failures + 1))
    else
      printf 'ok: inspect JSON contains no secret markers\n'
    fi
  fi

  if [[ "$failures" -gt 0 ]]; then
    printf 'zielwerk: target validation failed with %s error(s)\n' "$failures" >&2
    return 1
  fi

  printf 'zielwerk: target validation passed\n'
}

main() {
  if [[ $# -lt 1 ]]; then
    usage
    exit 2
  fi

  case "$1" in
    inspect)
      if [[ "${2:-}" == "--json" ]]; then
        [[ $# -eq 3 ]] || die "inspect --json requires exactly one target"
        [[ "$3" == "meow" ]] || die "unknown target '$3'"
        inspect_meow_json
      else
        [[ $# -eq 2 ]] || die "inspect requires exactly one target"
        [[ "$2" == "meow" ]] || die "unknown target '$2'"
        inspect_meow_text
      fi
      ;;
    validate-target)
      [[ $# -eq 2 || $# -eq 4 ]] || die "validate-target requires a target and optional --inspect-json <file>"
      if [[ $# -eq 4 ]]; then
        [[ "$3" == "--inspect-json" ]] || die "unknown validate-target option '$3'"
        validate_target "$2" "$4"
      else
        validate_target "$2"
      fi
      ;;
    -h|--help|help)
      usage
      ;;
    *)
      usage >&2
      exit 2
      ;;
  esac
}

main "$@"
