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

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
DEFAULT_BUNDLE_ROOT="$(cd "$DEPLOY_ROOT/.." && pwd)"

PROFILE=""
INVENTORY=""
CONFIG=""
SECRETS=""
BUNDLE_ROOT="$DEFAULT_BUNDLE_ROOT"
ALLOW_DEVELOPMENT="false"
ALLOW_PLAINTEXT_SECRETS="false"
TRUSTED_PUBLIC_KEY=""
PREFLIGHT_ONLY="false"
VERIFY_ONLY="false"
SKIP_APP="false"
RESUME_FROM="preflight"

usage() {
  cat >&2 <<'USAGE'
Usage:
  deploy.sh --profile single|ha --inventory <hosts.yml> --config <site.yml>
            --secrets <secrets.sops.yaml> [options]

Options:
  --bundle-root <path>
  --trusted-public-key <path>
  --allow-development-bundle
  --allow-plaintext-secrets
  --preflight-only
  --verify-only
  --skip-app
  --resume-from preflight|os-baseline|airgap|rke2|addons|application|verify
USAGE
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --profile) PROFILE="${2:?missing profile}"; shift 2 ;;
    --inventory) INVENTORY="${2:?missing inventory}"; shift 2 ;;
    --config) CONFIG="${2:?missing config}"; shift 2 ;;
    --secrets) SECRETS="${2:?missing secrets}"; shift 2 ;;
    --bundle-root) BUNDLE_ROOT="${2:?missing bundle root}"; shift 2 ;;
    --trusted-public-key) TRUSTED_PUBLIC_KEY="${2:?missing trusted public key}"; shift 2 ;;
    --allow-development-bundle) ALLOW_DEVELOPMENT="true"; shift ;;
    --allow-plaintext-secrets) ALLOW_PLAINTEXT_SECRETS="true"; shift ;;
    --preflight-only) PREFLIGHT_ONLY="true"; shift ;;
    --verify-only) VERIFY_ONLY="true"; shift ;;
    --skip-app) SKIP_APP="true"; shift ;;
    --resume-from) RESUME_FROM="${2:?missing phase}"; shift 2 ;;
    -h|--help) usage; exit 0 ;;
    *) echo "Unknown argument: $1" >&2; usage; exit 2 ;;
  esac
done

[[ "$PROFILE" == "single" || "$PROFILE" == "ha" ]] || { usage; exit 2; }
[[ -f "$INVENTORY" && -f "$CONFIG" && -f "$SECRETS" ]] || {
  echo "Inventory, config or secrets file is missing" >&2
  exit 2
}

BUNDLE_ROOT="$(cd "$BUNDLE_ROOT" && pwd)"
export PATH="$BUNDLE_ROOT/tools/bin:$PATH"
STATE_DIR="${TRACKWALKER_STATE_DIR:-$DEPLOY_ROOT/.state}"
mkdir -p "$STATE_DIR"
LOCK_DIR="$STATE_DIR/deploy.lock"
if ! mkdir "$LOCK_DIR" 2>/dev/null; then
  echo "Another deployment appears to be running: $LOCK_DIR" >&2
  exit 1
fi

umask 077
TEMP_DIR="$(mktemp -d "$STATE_DIR/run.XXXXXX")"
cleanup() {
  rm -rf "$TEMP_DIR"
  rmdir "$LOCK_DIR" 2>/dev/null || true
}
trap cleanup EXIT INT TERM

LOG_FILE="$STATE_DIR/deploy-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG_FILE") 2>&1

VERIFY_ARGS=(--bundle-root "$BUNDLE_ROOT")
if [[ -n "$TRUSTED_PUBLIC_KEY" ]]; then
  VERIFY_ARGS+=(--trusted-public-key "$TRUSTED_PUBLIC_KEY")
fi
RELEASE_VALIDATION=(--release)
if [[ "$ALLOW_DEVELOPMENT" == "true" ]]; then
  VERIFY_ARGS+=(--allow-development-bundle)
  RELEASE_VALIDATION=()
fi
"$SCRIPT_DIR/verify-bundle.sh" "${VERIFY_ARGS[@]}"

DECRYPTED_SECRETS="$TEMP_DIR/secrets.yaml"
if grep -q '^[[:space:]]*sops:' "$SECRETS"; then
  command -v sops >/dev/null 2>&1 || { echo "sops is required" >&2; exit 1; }
  sops --decrypt "$SECRETS" > "$DECRYPTED_SECRETS"
else
  [[ "$ALLOW_PLAINTEXT_SECRETS" == "true" ]] || {
    echo "Plaintext secrets require --allow-plaintext-secrets" >&2
    exit 1
  }
  cp "$SECRETS" "$DECRYPTED_SECRETS"
fi
chmod 0600 "$DECRYPTED_SECRETS"

python3 "$SCRIPT_DIR/validate_config.py" \
  --site "$CONFIG" \
  --inventory "$INVENTORY" \
  --secrets "$DECRYPTED_SECRETS" \
  --versions "$DEPLOY_ROOT/versions.lock.yaml" \
  "${RELEASE_VALIDATION[@]}"

CONFIG_PROFILE="$(python3 -c 'import sys,yaml; print(yaml.safe_load(open(sys.argv[1], encoding="utf-8"))["deployment"]["profile"])' "$CONFIG")"
[[ "$CONFIG_PROFILE" == "$PROFILE" ]] || {
  echo "CLI profile $PROFILE does not match site profile $CONFIG_PROFILE" >&2
  exit 1
}

export KUBECONFIG="${KUBECONFIG:-$STATE_DIR/kubeconfig}"
if [[ "$VERIFY_ONLY" == "true" ]]; then
  "$SCRIPT_DIR/verify.sh" "$CONFIG"
  exit 0
fi

case "$RESUME_FROM" in
  preflight) ANSIBLE_TAGS="preflight,os-baseline,airgap,rke2,postcheck" ;;
  os-baseline) ANSIBLE_TAGS="os-baseline,airgap,rke2,postcheck" ;;
  airgap) ANSIBLE_TAGS="airgap,rke2,postcheck" ;;
  rke2) ANSIBLE_TAGS="rke2,postcheck" ;;
  addons|application|verify) ANSIBLE_TAGS="" ;;
  *) echo "Unsupported resume phase: $RESUME_FROM" >&2; exit 2 ;;
esac

if [[ "$PREFLIGHT_ONLY" == "true" ]]; then
  ANSIBLE_TAGS="preflight"
fi

if [[ -n "$ANSIBLE_TAGS" ]]; then
  command -v ansible-playbook >/dev/null 2>&1 || { echo "ansible-playbook is required" >&2; exit 1; }
  ANSIBLE_CONFIG="$DEPLOY_ROOT/ansible/ansible.cfg" \
    ansible-playbook \
      --inventory "$INVENTORY" \
      "$DEPLOY_ROOT/ansible/site.yml" \
      --extra-vars "@$CONFIG" \
      --extra-vars "@$DECRYPTED_SECRETS" \
      --extra-vars "offline_artifact_root=$BUNDLE_ROOT" \
      --extra-vars "deployment_kubeconfig_path=$KUBECONFIG" \
      --tags "$ANSIBLE_TAGS"
fi

if [[ "$PREFLIGHT_ONLY" == "true" || "$SKIP_APP" == "true" ]]; then
  exit 0
fi

if [[ "$RESUME_FROM" != "application" && "$RESUME_FROM" != "verify" ]]; then
  "$SCRIPT_DIR/install-addons.sh" "$CONFIG" "$BUNDLE_ROOT" "$DEPLOY_ROOT"
fi

if [[ "$RESUME_FROM" != "verify" ]]; then
  command -v helm >/dev/null 2>&1 || { echo "helm is required" >&2; exit 1; }
  command -v kubectl >/dev/null 2>&1 || { echo "kubectl is required" >&2; exit 1; }

  NAMESPACE="$(python3 -c 'import sys,yaml; print(yaml.safe_load(open(sys.argv[1], encoding="utf-8"))["deployment"]["namespace"])' "$CONFIG")"
  RELEASE_NAME="$(python3 -c 'import sys,yaml; print(yaml.safe_load(open(sys.argv[1], encoding="utf-8"))["deployment"]["releaseName"])' "$CONFIG")"
  SECRET_NAME="$(python3 -c 'import sys,yaml; print(yaml.safe_load(open(sys.argv[1], encoding="utf-8"))["helmValues"]["global"]["existingSecret"])' "$CONFIG")"
  SECRET_ENV="$TEMP_DIR/application-secrets.env"
  SITE_VALUES="$TEMP_DIR/site-values.yaml"
  python3 "$SCRIPT_DIR/render_secret_env.py" --secrets "$DECRYPTED_SECRETS" --output "$SECRET_ENV"
  python3 "$SCRIPT_DIR/render_helm_values.py" \
    --site "$CONFIG" \
    --versions "$DEPLOY_ROOT/versions.lock.yaml" \
    --output "$SITE_VALUES"

  kubectl create namespace "$NAMESPACE" --dry-run=client -o yaml | kubectl apply -f -
  kubectl --namespace "$NAMESPACE" create secret generic "$SECRET_NAME" \
    --from-env-file "$SECRET_ENV" \
    --dry-run=client \
    -o yaml | kubectl apply -f -

  helm upgrade --install "$RELEASE_NAME" "$DEPLOY_ROOT/charts/trackwalker" \
    --namespace "$NAMESPACE" \
    --values "$DEPLOY_ROOT/charts/trackwalker/values.yaml" \
    --values "$DEPLOY_ROOT/charts/trackwalker/values-$PROFILE.yaml" \
    --values "$SITE_VALUES" \
    --wait \
    --timeout 20m \
    --atomic
fi

"$SCRIPT_DIR/verify.sh" "$CONFIG"
echo "Deployment completed. Log: $LOG_FILE"
