#!/usr/bin/env bash

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/../.." && pwd)"
DEFAULT_ENV_FILE="${SCRIPT_DIR}/enterprise.env"

usage() {
  cat <<'EOF'
Interactively write runtime and integration values into AWS SSM Parameter Store.

This helper uses the parameter names already stored in the enterprise env file:
  - SC_SSM_PARAM_MYSQL_ROOT_PASSWORD
  - SC_SSM_PARAM_MYSQL_APP_PASSWORD
  - SC_SSM_PARAM_REDIS_PASSWORD
  - SC_SSM_PARAM_JWT_ACCESS_SECRET
  - SC_SSM_PARAM_JWT_REFRESH_SECRET
  - SC_SSM_PARAM_AUTH0_CLIENT_SECRET
  - SC_SSM_PARAM_FEISHU_ORG_APP_ID
  - SC_SSM_PARAM_FEISHU_ORG_APP_SECRET
  - SC_SSM_PARAM_FEISHU_ALERT_APP_ID
  - SC_SSM_PARAM_FEISHU_ALERT_APP_SECRET
  - SC_DAST_API_TOKEN_PARAM
  - SC_DAST_CALLBACK_TOKEN_PARAM

Usage:
  ./scripts/enterprise/write-enterprise-ssm-secrets.sh --env-file ./scripts/enterprise/enterprise.env

Options:
  --env-file <path>              Enterprise env file. Default: scripts/enterprise/enterprise.env
  --profile <name>               AWS CLI profile override
  --region <name>                AWS region override
  --dry-run                      Print planned writes without updating SSM
  --non-interactive              Require values via explicit flags; do not prompt
  --generate-missing             In non-interactive mode, generate missing deploy
                                 secrets that have a safe generator
  --mysql-root-password <value>  MySQL root password override
  --mysql-app-password <value>   MySQL app password override
  --redis-password <value>       Redis password override
  --jwt-access-secret <value>    JWT access secret override
  --jwt-refresh-secret <value>   JWT refresh secret override
  --auth0-client-secret <value>  Real Auth0 client secret
  --feishu-org-app-id <value>    Feishu org sync app id
  --feishu-org-app-secret <v>    Feishu org sync app secret
  --feishu-alert-app-id <value>  Feishu alerts app id
  --feishu-alert-app-secret <v>  Feishu alerts app secret
  --dast-api-token <value>       Scanner API bearer token used by the asset backend
  --dast-callback-token <value>  Scanner callback token accepted by the asset backend
  --help                         Show this help
EOF
}

info() { echo "INFO: $*"; }
warn() { echo "WARN: $*" >&2; }
die() { echo "ERROR: $*" >&2; exit 1; }

trim() {
  local value="${1:-}"
  value="${value#"${value%%[![:space:]]*}"}"
  value="${value%"${value##*[![:space:]]}"}"
  printf '%s' "$value"
}

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

resolve_path() {
  local path="$1"
  if [[ "$path" = /* ]]; then
    printf '%s' "$path"
    return 0
  fi
  if [[ -e "$path" ]]; then
    printf '%s' "$path"
    return 0
  fi
  if [[ -e "${ROOT_DIR}/${path}" ]]; then
    printf '%s' "${ROOT_DIR}/${path}"
    return 0
  fi
  printf '%s' "$path"
}

get_env_value() {
  local env_file="$1"
  local key="$2"
  [[ -f "${env_file}" ]] || return 0
  python3 - "$env_file" "$key" <<'PY'
from pathlib import Path
import sys

path = Path(sys.argv[1])
key = sys.argv[2]
for raw in path.read_text().splitlines():
    line = raw.strip()
    if not line or line.startswith("#") or "=" not in line:
        continue
    lhs, rhs = line.split("=", 1)
    if lhs.strip() == key:
        print(rhs.strip())
        break
PY
}

prompt_yes_no() {
  local __var="$1"
  local message="$2"
  local default="${3:-y}"
  local answer=""

  if [[ "${NON_INTERACTIVE}" == "true" ]]; then
    case "${default}" in
      y|Y|yes|YES|true) printf -v "$__var" '%s' "true" ;;
      *) printf -v "$__var" '%s' "false" ;;
    esac
    return 0
  fi

  while true; do
    printf "%s [%s]: " "$message" "$default"
    IFS= read -r answer || true
    answer="$(trim "$answer")"
    [[ -z "${answer}" ]] && answer="${default}"
    case "${answer}" in
      y|Y|yes|YES|true|TRUE) printf -v "$__var" '%s' "true"; return 0 ;;
      n|N|no|NO|false|FALSE) printf -v "$__var" '%s' "false"; return 0 ;;
      *) warn "Please answer y or n." ;;
    esac
  done
}

prompt_secret_or_skip() {
  local __var="$1"
  local message="$2"
  local captured_value=""

  if [[ "${NON_INTERACTIVE}" == "true" ]]; then
    die "missing required non-interactive value: ${message}"
  fi

  printf "%s (leave blank to skip): " "$message" >&2
  IFS= read -r captured_value || true
  captured_value="$(trim "$captured_value")"
  printf -v "$__var" '%s' "$captured_value"
}

prompt_value_or_skip() {
  local __var="$1"
  local message="$2"
  local captured_value=""

  if [[ "${NON_INTERACTIVE}" == "true" ]]; then
    die "missing required non-interactive value: ${message}"
  fi

  printf "%s (leave blank to skip): " "$message" >&2
  IFS= read -r captured_value || true
  captured_value="$(trim "$captured_value")"
  printf -v "$__var" '%s' "$captured_value"
}

is_prod_external_secret_label() {
  case "${1:-}" in
    "Auth0 client secret"|"Feishu org sync app id"|"Feishu org sync app secret"|"Feishu alerts app id"|"Feishu alerts app secret")
      [[ "${ENVIRONMENT_MODE:-prod}" == "prod" ]]
      ;;
    *)
      return 1
      ;;
  esac
}

prompt_parameter_value() {
  local __var="$1"
  local label="$2"
  local input_mode="${3:-secret}"
  local input_value=""
  local retry_input="false"

  while true; do
    if [[ "${input_mode}" == "visible" ]]; then
      prompt_value_or_skip input_value "${label}"
    else
      prompt_secret_or_skip input_value "${label}"
    fi

    if [[ -n "${input_value}" ]]; then
      if is_prod_external_secret_label "${label}"; then
        info "received non-empty value for ${label}"
      fi
      printf -v "$__var" '%s' "$input_value"
      return 0
    fi

    if is_prod_external_secret_label "${label}"; then
      warn "no value captured for ${label}"
      prompt_yes_no retry_input "Retry entering ${label} now" "y"
      if [[ "${retry_input}" == "true" ]]; then
        continue
      fi
    fi

    printf -v "$__var" '%s' ""
    return 0
  done
}

generate_secret_value() {
  local kind="${1:-token}"
  python3 - "${kind}" <<'PY'
import secrets
import string
import sys

kind = sys.argv[1]
if kind == "password":
    alphabet = string.ascii_letters + string.digits + "-_.!@#%^&*+="
    print("".join(secrets.choice(alphabet) for _ in range(32)))
elif kind == "mysql_root":
    alphabet = string.ascii_letters + string.digits + "!@#%^&*-_+="
    print("".join(secrets.choice(alphabet) for _ in range(40)))
else:
    print(secrets.token_urlsafe(48))
PY
}

parameter_exists() {
  local name="$1"
  aws ssm get-parameter --region "${AWS_REGION_NAME}" --name "${name}" --query 'Parameter.Version' --output text >/dev/null 2>&1
}

put_secure_parameter() {
  local name="$1"
  local value="$2"
  [[ -n "${name}" ]] || die "parameter name is required"
  if [[ "${DRY_RUN}" == "true" ]]; then
    info "would write SecureString parameter: ${name}"
    return 0
  fi
  aws ssm put-parameter \
    --region "${AWS_REGION_NAME}" \
    --name "${name}" \
    --type SecureString \
    --value "${value}" \
    --overwrite >/dev/null
}

process_secret_parameter() {
  local label="$1"
  local param_name="$2"
  local provided_value="${3:-}"
  local input_mode="${4:-secret}"
  local generate_kind="${5:-}"
  local value="${provided_value}"
  local write_choice="true"
  local exists="false"

  [[ -n "${param_name}" ]] || {
    warn "skipping ${label}: missing parameter name in env file"
    return 0
  }

  if parameter_exists "${param_name}"; then
    exists="true"
  fi

  if [[ -z "${value}" ]]; then
    if [[ "${GENERATE_MISSING}" == "true" && "${exists}" != "true" && -n "${generate_kind}" ]]; then
      value="$(generate_secret_value "${generate_kind}")"
    fi
  fi

  if [[ -z "${value}" ]]; then
    if [[ "${NON_INTERACTIVE}" == "true" ]]; then
      return 0
    fi
    if [[ "${exists}" == "true" ]]; then
      prompt_yes_no write_choice "Overwrite existing ${label} at ${param_name}" "n"
      [[ "${write_choice}" == "true" ]] || {
        info "kept existing value for ${label}: ${param_name}"
        return 0
      }
    else
      prompt_yes_no write_choice "Write ${label} to ${param_name}" "y"
      [[ "${write_choice}" == "true" ]] || {
        info "skipped ${label}: ${param_name}"
        return 0
      }
    fi
    if [[ -n "${generate_kind}" ]]; then
      local generate_now="true"
      prompt_yes_no generate_now "Generate a recommended ${label} automatically" "y"
      if [[ "${generate_now}" == "true" ]]; then
        value="$(generate_secret_value "${generate_kind}")"
      else
        prompt_parameter_value value "${label}" "secret"
      fi
    else
      prompt_parameter_value value "${label}" "${input_mode}"
    fi
    [[ -n "${value}" ]] || {
      info "skipped ${label}: no value entered"
      return 0
    }
  fi

  put_secure_parameter "${param_name}" "${value}"
  info "updated ${label}: ${param_name}"
}

ENV_FILE="${DEFAULT_ENV_FILE}"
AWS_PROFILE_NAME="${AWS_PROFILE:-}"
AWS_REGION_NAME="${AWS_REGION:-${AWS_DEFAULT_REGION:-}}"
DRY_RUN="false"
NON_INTERACTIVE="false"
GENERATE_MISSING="false"
MYSQL_ROOT_PASSWORD_VALUE=""
MYSQL_APP_PASSWORD_VALUE=""
REDIS_PASSWORD_VALUE=""
JWT_ACCESS_SECRET_VALUE=""
JWT_REFRESH_SECRET_VALUE=""
AUTH0_CLIENT_SECRET_VALUE=""
FEISHU_ORG_APP_ID_VALUE=""
FEISHU_ORG_APP_SECRET_VALUE=""
FEISHU_ALERT_APP_ID_VALUE=""
FEISHU_ALERT_APP_SECRET_VALUE=""
DAST_API_TOKEN_VALUE=""
DAST_CALLBACK_TOKEN_VALUE=""

while (($# > 0)); do
  case "$1" in
    --env-file)
      ENV_FILE="$2"
      shift 2
      ;;
    --profile)
      AWS_PROFILE_NAME="$2"
      shift 2
      ;;
    --region)
      AWS_REGION_NAME="$2"
      shift 2
      ;;
    --mysql-root-password)
      MYSQL_ROOT_PASSWORD_VALUE="$2"
      shift 2
      ;;
    --mysql-app-password)
      MYSQL_APP_PASSWORD_VALUE="$2"
      shift 2
      ;;
    --redis-password)
      REDIS_PASSWORD_VALUE="$2"
      shift 2
      ;;
    --jwt-access-secret)
      JWT_ACCESS_SECRET_VALUE="$2"
      shift 2
      ;;
    --jwt-refresh-secret)
      JWT_REFRESH_SECRET_VALUE="$2"
      shift 2
      ;;
    --auth0-client-secret)
      AUTH0_CLIENT_SECRET_VALUE="$2"
      shift 2
      ;;
    --feishu-org-app-id)
      FEISHU_ORG_APP_ID_VALUE="$2"
      shift 2
      ;;
    --feishu-org-app-secret)
      FEISHU_ORG_APP_SECRET_VALUE="$2"
      shift 2
      ;;
    --feishu-alert-app-id)
      FEISHU_ALERT_APP_ID_VALUE="$2"
      shift 2
      ;;
    --feishu-alert-app-secret)
      FEISHU_ALERT_APP_SECRET_VALUE="$2"
      shift 2
      ;;
    --dast-api-token)
      DAST_API_TOKEN_VALUE="$2"
      shift 2
      ;;
    --dast-callback-token)
      DAST_CALLBACK_TOKEN_VALUE="$2"
      shift 2
      ;;
    --dry-run)
      DRY_RUN="true"
      shift
      ;;
    --non-interactive)
      NON_INTERACTIVE="true"
      shift
      ;;
    --generate-missing)
      GENERATE_MISSING="true"
      shift
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    *)
      die "unknown argument: $1"
      ;;
  esac
done

ENV_FILE="$(resolve_path "${ENV_FILE}")"
[[ -f "${ENV_FILE}" ]] || die "env file not found: ${ENV_FILE}"
[[ -n "${AWS_REGION_NAME}" ]] || die "AWS region is required; pass --region or set SC_AWS_REGION in the env file"
require_bin aws

if [[ -n "${AWS_PROFILE_NAME}" ]]; then
  export AWS_PROFILE="${AWS_PROFILE_NAME}"
  export AWS_SDK_LOAD_CONFIG=1
fi
export AWS_REGION="${AWS_REGION_NAME}"
export AWS_DEFAULT_REGION="${AWS_REGION_NAME}"

ENVIRONMENT_MODE="$(trim "$(get_env_value "${ENV_FILE}" "SC_ENVIRONMENT_MODE")")"
[[ -n "${ENVIRONMENT_MODE}" ]] || ENVIRONMENT_MODE="prod"

MYSQL_ROOT_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_MYSQL_ROOT_PASSWORD")")"
MYSQL_APP_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_MYSQL_APP_PASSWORD")")"
REDIS_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_REDIS_PASSWORD")")"
JWT_ACCESS_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_JWT_ACCESS_SECRET")")"
JWT_REFRESH_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_JWT_REFRESH_SECRET")")"
AUTH0_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_AUTH0_CLIENT_SECRET")")"
FEISHU_ORG_ID_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_FEISHU_ORG_APP_ID")")"
FEISHU_ORG_SECRET_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_FEISHU_ORG_APP_SECRET")")"
FEISHU_ALERT_ID_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_FEISHU_ALERT_APP_ID")")"
FEISHU_ALERT_SECRET_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_SSM_PARAM_FEISHU_ALERT_APP_SECRET")")"
DAST_API_TOKEN_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_DAST_API_TOKEN_PARAM")")"
DAST_CALLBACK_TOKEN_PARAM="$(trim "$(get_env_value "${ENV_FILE}" "SC_DAST_CALLBACK_TOKEN_PARAM")")"

if [[ -n "${DAST_API_TOKEN_VALUE}" && -n "${DAST_CALLBACK_TOKEN_VALUE}" && "${DAST_API_TOKEN_VALUE}" == "${DAST_CALLBACK_TOKEN_VALUE}" ]]; then
  die "scanner API token and callback token must be different"
fi

info "writing enterprise secrets to AWS SSM Parameter Store"
info "  - env file: ${ENV_FILE}"
info "  - aws profile: ${AWS_PROFILE_NAME:-<default>}"
info "  - aws region: ${AWS_REGION_NAME}"

info "runtime secret section:"
info "  - MySQL / Redis / JWT values can be generated automatically here."
process_secret_parameter "MySQL root password" "${MYSQL_ROOT_PARAM}" "${MYSQL_ROOT_PASSWORD_VALUE}" "secret" "mysql_root"
process_secret_parameter "MySQL app password" "${MYSQL_APP_PARAM}" "${MYSQL_APP_PASSWORD_VALUE}" "secret" "password"
process_secret_parameter "Redis password" "${REDIS_PARAM}" "${REDIS_PASSWORD_VALUE}" "secret" "password"
process_secret_parameter "JWT access secret" "${JWT_ACCESS_PARAM}" "${JWT_ACCESS_SECRET_VALUE}" "secret" "token"
process_secret_parameter "JWT refresh secret" "${JWT_REFRESH_PARAM}" "${JWT_REFRESH_SECRET_VALUE}" "secret" "token"

info "external integration secret section:"
process_secret_parameter "Auth0 client secret" "${AUTH0_PARAM}" "${AUTH0_CLIENT_SECRET_VALUE}"
process_secret_parameter "Feishu org sync app id" "${FEISHU_ORG_ID_PARAM}" "${FEISHU_ORG_APP_ID_VALUE}" "visible"
process_secret_parameter "Feishu org sync app secret" "${FEISHU_ORG_SECRET_PARAM}" "${FEISHU_ORG_APP_SECRET_VALUE}"
process_secret_parameter "Feishu alerts app id" "${FEISHU_ALERT_ID_PARAM}" "${FEISHU_ALERT_APP_ID_VALUE}" "visible"
process_secret_parameter "Feishu alerts app secret" "${FEISHU_ALERT_SECRET_PARAM}" "${FEISHU_ALERT_APP_SECRET_VALUE}"

info "scanner integration secret section:"
info "  - these are shared integration tokens only; scanner database, Redis, TLS key, and internal runtime secrets remain owned by the scanner deployment."
process_secret_parameter "Scanner API token" "${DAST_API_TOKEN_PARAM}" "${DAST_API_TOKEN_VALUE}" "secret" "token"
process_secret_parameter "Scanner callback token" "${DAST_CALLBACK_TOKEN_PARAM}" "${DAST_CALLBACK_TOKEN_VALUE}" "secret" "token"

info "done. deployment-time runtime secrets still require --resolve-ssm, and Feishu values still need post-deploy settings bootstrap."
