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

log() {
  printf '%s %s\n' "$(date '+%Y-%m-%dT%H:%M:%S%z')" "$*"
}

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

require_cmd() {
  command -v "$1" >/dev/null 2>&1 || die "required command not found: $1"
}

require_file() {
  [ -f "$1" ] || die "required file not found: $1"
}

load_env_file() {
  local env_file="$1"
  require_file "$env_file"
  while IFS= read -r line || [ -n "$line" ]; do
    line="${line%$'\r'}"
    case "$line" in
      ''|'#'*) continue ;;
    esac
    [[ "$line" == *=* ]] || die "invalid env line in $env_file"
    local key="${line%%=*}"
    local value="${line#*=}"
    [[ "$key" =~ ^[A-Z][A-Z0-9_]*$ ]] || die "invalid env key in $env_file: $key"
    export "$key=$value"
  done < "$env_file"
}

assert_no_placeholders() {
  local env_file="$1"
  if grep -Eq '^[A-Z][A-Z0-9_]*=.*(REQUIRED|CHANGE_ME|TODO)' "$env_file"; then
    die "unfilled placeholder found in $env_file"
  fi
}

sha256_file() {
  if command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
  else
    shasum -a 256 "$1" | awk '{print $1}'
  fi
}

verify_sha256() {
  local file="$1"
  local expected="$2"
  require_file "$file"
  local actual
  actual="$(sha256_file "$file")"
  [ "$actual" = "$expected" ] || die "sha256 mismatch for $file"
}

require_secret_permissions() {
  local file="$1"
  require_file "$file"
  local mode
  if stat -c '%a' "$file" >/dev/null 2>&1; then
    mode="$(stat -c '%a' "$file")"
  else
    mode="$(stat -f '%Lp' "$file")"
  fi
  case "$mode" in
    600|400) ;;
    *) die "secret file must be mode 600 or 400: $file (mode=$mode)" ;;
  esac
}

require_apply_authorization() {
  local action="$1"
  local approval_file="$2"
  local host_ref="$3"
  require_secret_permissions "$approval_file"
  load_env_file "$approval_file"
  [ "${APPROVED_ACTION:-}" = "$action" ] || die "approval action mismatch"
  [ "${APPROVED_HOST_REF:-}" = "$host_ref" ] || die "approval host mismatch"
  [ -n "${APPROVED_BY:-}" ] || die "APPROVED_BY is required"
  [ -n "${CHANGE_WINDOW_START:-}" ] || die "CHANGE_WINDOW_START is required"
  [ -n "${CHANGE_WINDOW_END:-}" ] || die "CHANGE_WINDOW_END is required"
  [ -n "${BACKUP_REF:-}" ] || die "BACKUP_REF is required"
}

validate_project_root() {
  local root="$1"
  case "$root" in
    /workspace/wwwroot/*/project|/workspace/wwwroot/*/project/public/store) ;;
    *) die "unsafe project root: $root" ;;
  esac
  [ "$root" != "/" ] || die "root path forbidden"
}

network_tcp_check() {
  local host="$1"
  local port="$2"
  if command -v timeout >/dev/null 2>&1; then
    timeout 5 bash -c "exec 3<>/dev/tcp/${host}/${port}" >/dev/null 2>&1
  else
    bash -c "exec 3<>/dev/tcp/${host}/${port}" >/dev/null 2>&1
  fi
}
