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

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
SRC_DIR="${ROOT_DIR}/src"

VENV_DIR="${VENV_DIR:-${ROOT_DIR}/.venv}"
PYTHON_BIN="${PYTHON_BIN:-python3}"

MODE="run"
DRY_RUN=0
SKIP_INSTALL=0
VERBOSE=0
PERMISSION_CHECK=1
PERMISSION_CHECK_ONLY=0
CONFIGURE_PROFILE=0
CONFIG_PATH="${SRC_DIR}/roles_config.json"
REGION=""
ACCESS_KEY_ID=""
ACCESS_KEY_SECRET=""
PROFILE=""
ONE_CLICK_PERMISSION_CHECK_CMD="${ONE_CLICK_PERMISSION_CHECK_CMD:-}"
ALIYUN_CLI_BIN="${ALIYUN_CLI_BIN:-aliyun}"

REQUIRED_PERMISSIONS=(
  "cloudsso:ListAccessConfigurations"
  "cloudsso:CreateAccessConfiguration"
  "cloudsso:AddPermissionPolicyToAccessConfiguration"
)

EXTRA_ARGS=()
ORIGINAL_ARGC=$#

usage() {
  cat <<'USAGE'
One-click runner for CloudSSO role creator

Usage:
  script/one-click.sh [options] [-- extra_app_args]

Options:
  --mode <run|test|setup>   Choose action mode (default: run)
  --config <path>           Config file path (default: src/roles_config.json)
  --region <region>         Region override for run mode
  --access-key-id <ak>      Access key id for run mode
  --access-key-secret <sk>  Access key secret for run mode
  --profile <name>          Alibaba Cloud profile name for guidance (default: default)
  --configure-profile       Run aliyun profile configure + sso login before run
  --verbose, -v             Enable verbose mode for run mode
  --skip-permission-check   Skip CloudSSO permission preflight in run mode
  --permission-check-only   Only run permission preflight then exit
  --no-install              Skip dependency installation
  --dry-run                 Print commands without executing
  --help, -h                Show this help

Examples:
  script/one-click.sh
  script/one-click.sh --mode test
  script/one-click.sh --mode run --region cn-shanghai --verbose
  script/one-click.sh --mode run --profile default
  script/one-click.sh --mode run --configure-profile --profile default
  script/one-click.sh --permission-check-only
USAGE
}

log() {
  printf '[one-click] %s\n' "$*"
}

run_cmd() {
  if [[ "${DRY_RUN}" -eq 1 ]]; then
    log "DRY RUN: $*"
    return 0
  fi
  "$@"
}

command_exists() {
  command -v "$1" >/dev/null 2>&1
}

aliyun_supports_sso_command() {
  if [[ "${DRY_RUN}" -eq 1 ]]; then
    return 0
  fi
  if ! command_exists "${ALIYUN_CLI_BIN}"; then
    return 1
  fi
  if "${ALIYUN_CLI_BIN}" sso login --help >/dev/null 2>&1; then
    return 0
  fi
  if "${ALIYUN_CLI_BIN}" sso --help >/dev/null 2>&1; then
    return 0
  fi
  return 1
}

resolve_profile_name() {
  if [[ -n "${PROFILE}" ]]; then
    printf '%s' "${PROFILE}"
    return 0
  fi
  if [[ -n "${ALIBABA_CLOUD_PROFILE:-}" ]]; then
    printf '%s' "${ALIBABA_CLOUD_PROFILE}"
    return 0
  fi
  if [[ -n "${ALIYUN_PROFILE:-}" ]]; then
    printf '%s' "${ALIYUN_PROFILE}"
    return 0
  fi
  printf 'default'
}

has_explicit_ak_credentials() {
  if [[ -n "${ACCESS_KEY_ID}" && -n "${ACCESS_KEY_SECRET}" ]]; then
    return 0
  fi
  if [[ -n "${ALIBABA_CLOUD_ACCESS_KEY_ID:-}" && -n "${ALIBABA_CLOUD_ACCESS_KEY_SECRET:-}" ]]; then
    return 0
  fi
  return 1
}

credentials_file_path() {
  if [[ -n "${ALIBABA_CLOUD_CREDENTIALS_FILE:-}" ]]; then
    printf '%s' "${ALIBABA_CLOUD_CREDENTIALS_FILE}"
    return 0
  fi
  printf '%s/.alibabacloud/credentials.ini' "${HOME}"
}

has_static_credentials_file() {
  local credential_file
  credential_file="$(credentials_file_path)"
  [[ -s "${credential_file}" ]]
}

sso_profile_exists() {
  local profile_name="$1"
  local config_file="${HOME}/.aliyun/config.json"
  if [[ ! -s "${config_file}" ]]; then
    return 1
  fi

  python3 - "${config_file}" "${profile_name}" <<'PY' >/dev/null 2>&1
import json
import sys

config_file = sys.argv[1]
profile_name = sys.argv[2]

try:
    with open(config_file, "r", encoding="utf-8") as f:
        raw = json.load(f)
except Exception:
    raise SystemExit(1)

profiles = []
if isinstance(raw, dict):
    profile_list = raw.get("profiles")
    if isinstance(profile_list, list):
        profiles.extend([item for item in profile_list if isinstance(item, dict)])
    elif isinstance(profile_list, dict):
        if profile_name in profile_list:
            raise SystemExit(0)

for item in profiles:
    name = str(item.get("name", "")).strip()
    if name == profile_name:
        raise SystemExit(0)

raise SystemExit(1)
PY
}

print_credential_setup_guidance() {
  local profile_name
  profile_name="$(resolve_profile_name)"

  log "Credential setup options (choose one):"
  log "  1) Use CLI args: --access-key-id <ak> --access-key-secret <sk>"
  log "  2) Use env vars: export ALIBABA_CLOUD_ACCESS_KEY_ID=... and ALIBABA_CLOUD_ACCESS_KEY_SECRET=..."
  log "  3) Use Alibaba Cloud SSO profile:"
  log "     aliyun configure --mode StsToken --profile ${profile_name}"
  log "     aliyun sso login --profile ${profile_name}"
  log "     Or run this script with: --configure-profile --profile ${profile_name}"

  if [[ "${ALIBABA_CLOUD_CREDENTIALS_FILE:-}" == \$* ]]; then
    log "Detected invalid ALIBABA_CLOUD_CREDENTIALS_FILE: ${ALIBABA_CLOUD_CREDENTIALS_FILE}"
    log "Set it to an absolute path or unset it before retry."
  fi
}

print_required_permissions() {
  log "Required permissions:"
  for permission in "${REQUIRED_PERMISSIONS[@]}"; do
    log "  - ${permission}"
  done
}

print_directory_setup_guidance() {
  log "Directory preflight failed: DirectoryId does not exist for current account/region."
  log "Check config file '${CONFIG_PATH}' and update:"
  log "  - DirectoryId: must be your real CloudSSO directory id (not a placeholder)"
  log "  - Region: must match your CloudSSO directory region"
  log "You can also override region at runtime with: --region <region-id>"
}

is_access_denied_text() {
  local content="${1:-}"
  printf '%s' "${content}" | grep -Eiq \
    'accessdenied|forbidden|unauthorized|not[[:space:]]+authorized|permission'
}

is_credential_error_text() {
  local content="${1:-}"
  printf '%s' "${content}" | grep -Eiq \
    'unable to load credentials|access token is empty or expired|failed to get credential|refresh credentials failed|security-credentials|environment variable accesskeyid cannot be empty'
}

is_directory_error_text() {
  local content="${1:-}"
  printf '%s' "${content}" | grep -Eiq \
    'entitynotexists\.directory|directory does not exist'
}

is_sso_unsupported_text() {
  local content="${1:-}"
  printf '%s' "${content}" | grep -Eiq \
    "not a valid command or product|unknown command|invalid command|did you mean:"
}

run_profile_setup_flow() {
  local profile_name
  profile_name="$(resolve_profile_name)"

  if [[ "${DRY_RUN}" -eq 0 ]] && ! command_exists "${ALIYUN_CLI_BIN}"; then
    log "Alibaba Cloud CLI not found: ${ALIYUN_CLI_BIN}"
    log "Install Alibaba Cloud CLI first, then rerun."
    return 1
  fi

  log "Starting Alibaba Cloud profile setup for '${profile_name}'."
  log "Follow CLI prompts to provide AccessKey ID / AccessKey Secret / SecurityToken / Region ID as required."
  run_cmd "${ALIYUN_CLI_BIN}" configure --mode StsToken --profile "${profile_name}"

  if aliyun_supports_sso_command; then
    log "Starting Alibaba Cloud SSO login for profile '${profile_name}'."
    if [[ "${DRY_RUN}" -eq 1 ]]; then
      run_cmd "${ALIYUN_CLI_BIN}" sso login --profile "${profile_name}"
      return 0
    fi

    local sso_output
    if sso_output="$("${ALIYUN_CLI_BIN}" sso login --profile "${profile_name}" 2>&1)"; then
      if [[ -n "${sso_output}" ]]; then
        printf '%s\n' "${sso_output}"
      fi
      return 0
    fi

    printf '%s\n' "${sso_output}" >&2
    if is_sso_unsupported_text "${sso_output}"; then
      log "Local aliyun CLI reports no 'sso' command; skipping this step."
      log "If your token is not ready, update aliyun CLI or configure STS token manually."
      return 0
    fi
    log "Failed to run 'aliyun sso login --profile ${profile_name}'."
    return 1
  else
    log "Local aliyun CLI does not support 'aliyun sso login'; skipping this step."
    log "If your token is not ready, update aliyun CLI or configure STS token manually."
  fi
  return 0
}

prompt_profile_setup_if_interactive() {
  local profile_name
  profile_name="$(resolve_profile_name)"

  if [[ ! -t 0 ]]; then
    return 1
  fi

  printf '[one-click] Local SSO profile "%s" is not configured. Configure now? [y/N]: ' "${profile_name}" >&2
  local answer
  read -r answer || true
  case "${answer}" in
    y|Y|yes|YES)
      run_profile_setup_flow || return 1
      return 0
      ;;
    *)
      return 1
      ;;
  esac
}

check_local_credential_prerequisites() {
  if has_explicit_ak_credentials; then
    return 0
  fi
  if has_static_credentials_file; then
    return 0
  fi

  local profile_name
  profile_name="$(resolve_profile_name)"
  if sso_profile_exists "${profile_name}"; then
    return 0
  fi

  if prompt_profile_setup_if_interactive; then
    return 0
  fi

  log "No explicit credentials found and no local SSO profile '${profile_name}' is configured."
  print_credential_setup_guidance
  return 1
}

run_permission_preflight() {
  if [[ "${MODE}" != "run" ]]; then
    return 0
  fi
  if [[ "${PERMISSION_CHECK}" -eq 0 ]]; then
    log "Permission preflight skipped by flag."
    return 0
  fi

  log "Running CloudSSO permission preflight..."
  if [[ "${DRY_RUN}" -eq 1 ]]; then
    log "DRY RUN: permission preflight for DirectoryId from ${CONFIG_PATH}"
    print_required_permissions
    return 0
  fi

  if [[ -n "${ONE_CLICK_PERMISSION_CHECK_CMD}" ]]; then
    local override_output
    if override_output="$(bash -lc "${ONE_CLICK_PERMISSION_CHECK_CMD}" 2>&1)"; then
      log "Permission preflight passed."
      return 0
    fi

    printf '%s\n' "${override_output}" >&2
    if is_directory_error_text "${override_output}"; then
      print_directory_setup_guidance
    elif is_credential_error_text "${override_output}"; then
      log "Credential preflight failed."
      print_credential_setup_guidance
    elif is_access_denied_text "${override_output}"; then
      log "Permission preflight failed: insufficient permissions."
      print_required_permissions
    else
      log "Permission preflight failed unexpectedly."
    fi
    return 4
  fi

  if ! check_local_credential_prerequisites; then
    return 5
  fi

  if [[ ! -x "${VENV_DIR}/bin/python" ]]; then
    log "Permission preflight failed: ${VENV_DIR}/bin/python not found."
    print_required_permissions
    return 4
  fi

  local check_output
  if check_output="$(
    PYTHONPATH="${SRC_DIR}${PYTHONPATH:+:${PYTHONPATH}}" \
      "${VENV_DIR}/bin/python" - "${CONFIG_PATH}" "${REGION}" "${ACCESS_KEY_ID}" "${ACCESS_KEY_SECRET}" 2>&1 <<'PY'
from __future__ import annotations

import sys

from sso_role_creator.client import create_cloudsso_client
from sso_role_creator.config import load_config
from sso_role_creator.creator import _load_cloudsso_models

config_path = sys.argv[1]
region_override = sys.argv[2] or None
access_key_id = sys.argv[3] or None
access_key_secret = sys.argv[4] or None

config = load_config(config_path, region_override)
client = create_cloudsso_client(
    region=config.region,
    access_key_id=access_key_id,
    access_key_secret=access_key_secret,
)
models = _load_cloudsso_models()
request = models.ListAccessConfigurationsRequest(
    directory_id=config.directory_id,
)
client.list_access_configurations(request)
print("permission preflight passed")
PY
  )"; then
    log "Permission preflight passed."
    return 0
  fi

  printf '%s\n' "${check_output}" >&2
  if is_directory_error_text "${check_output}"; then
    print_directory_setup_guidance
  elif is_credential_error_text "${check_output}"; then
    log "Credential preflight failed."
    print_credential_setup_guidance
  elif is_access_denied_text "${check_output}"; then
    log "Permission preflight failed: insufficient permissions."
    print_required_permissions
  else
    log "Permission preflight failed. Please verify credentials, network, and region."
  fi
  return 4
}

ensure_venv() {
  if [[ ! -d "${VENV_DIR}" ]]; then
    log "Creating virtual environment at ${VENV_DIR}"
    run_cmd "${PYTHON_BIN}" -m venv "${VENV_DIR}"
  fi

  if [[ "${SKIP_INSTALL}" -eq 0 ]]; then
    log "Installing dependencies from ${SRC_DIR}/requirements.txt"
    run_cmd "${VENV_DIR}/bin/pip" install -r "${SRC_DIR}/requirements.txt"
  fi
}

interactive_pick_mode() {
  log "Select mode:"
  echo "  1) run  (recommended)"
  echo "  2) test"
  echo "  3) setup"
  printf 'Enter choice [1-3]: '
  read -r choice
  case "${choice}" in
    1|"") MODE="run" ;;
    2) MODE="test" ;;
    3) MODE="setup" ;;
    *)
      log "Invalid choice: ${choice}"
      exit 2
      ;;
  esac
}

while [[ $# -gt 0 ]]; do
  case "$1" in
    --mode)
      MODE="${2:-}"
      shift 2
      ;;
    --config)
      CONFIG_PATH="${2:-}"
      shift 2
      ;;
    --region)
      REGION="${2:-}"
      shift 2
      ;;
    --access-key-id)
      ACCESS_KEY_ID="${2:-}"
      shift 2
      ;;
    --access-key-secret)
      ACCESS_KEY_SECRET="${2:-}"
      shift 2
      ;;
    --profile)
      PROFILE="${2:-}"
      shift 2
      ;;
    --configure-profile)
      CONFIGURE_PROFILE=1
      shift
      ;;
    --verbose|-v)
      VERBOSE=1
      shift
      ;;
    --skip-permission-check)
      PERMISSION_CHECK=0
      shift
      ;;
    --permission-check-only)
      PERMISSION_CHECK_ONLY=1
      shift
      ;;
    --dry-run)
      DRY_RUN=1
      shift
      ;;
    --no-install)
      SKIP_INSTALL=1
      shift
      ;;
    --help|-h)
      usage
      exit 0
      ;;
    --)
      shift
      EXTRA_ARGS+=("$@")
      break
      ;;
    *)
      EXTRA_ARGS+=("$1")
      shift
      ;;
  esac
done

if [[ "${MODE}" != "run" && "${MODE}" != "test" && "${MODE}" != "setup" ]]; then
  log "Unsupported mode: ${MODE}"
  usage
  exit 2
fi

if [[ -n "${PROFILE}" ]]; then
  export ALIBABA_CLOUD_PROFILE="${PROFILE}"
  export ALIYUN_PROFILE="${PROFILE}"
fi

if [[ "${ORIGINAL_ARGC}" -eq 0 && -t 0 && "${DRY_RUN}" -eq 0 && "${MODE}" == "run" && "${#EXTRA_ARGS[@]}" -eq 0 ]]; then
  interactive_pick_mode
fi

ensure_venv

if [[ "${MODE}" == "setup" ]]; then
  log "Setup completed. Use: source ${VENV_DIR}/bin/activate"
  exit 0
fi

if [[ "${MODE}" == "test" ]]; then
  CMD=("${VENV_DIR}/bin/python" -m pytest "${SRC_DIR}/tests" -q)
  if [[ "${#EXTRA_ARGS[@]}" -gt 0 ]]; then
    CMD+=("${EXTRA_ARGS[@]}")
  fi
  run_cmd "${CMD[@]}"
  exit 0
fi

if [[ "${CONFIGURE_PROFILE}" -eq 1 ]]; then
  run_profile_setup_flow
fi

run_permission_preflight
if [[ "${PERMISSION_CHECK_ONLY}" -eq 1 ]]; then
  log "Permission check completed."
  exit 0
fi

CMD=("${VENV_DIR}/bin/python" "${SRC_DIR}/main.py" --config "${CONFIG_PATH}")
if [[ -n "${REGION}" ]]; then
  CMD+=(--region "${REGION}")
fi
if [[ -n "${ACCESS_KEY_ID}" ]]; then
  CMD+=(--access-key-id "${ACCESS_KEY_ID}")
fi
if [[ -n "${ACCESS_KEY_SECRET}" ]]; then
  CMD+=(--access-key-secret "${ACCESS_KEY_SECRET}")
fi
if [[ "${VERBOSE}" -eq 1 ]]; then
  CMD+=(--verbose)
fi
if [[ "${#EXTRA_ARGS[@]}" -gt 0 ]]; then
  CMD+=("${EXTRA_ARGS[@]}")
fi

run_cmd "${CMD[@]}"
