#!/usr/bin/env bash

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

# Create or reconnect to an OpenShell development sandbox on the active gateway.

set -euo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
OPENSHELL_BIN="${OPENSHELL_BIN:-${ROOT}/scripts/bin/openshell}"
SANDBOX_NAME="${OPENSHELL_DEVSHELL_SANDBOX:-openshell-dev}"
SANDBOX_IMAGE="${OPENSHELL_DEVSHELL_IMAGE:-openshell/ci:dev}"
BOOTSTRAP_FILE="${OPENSHELL_DEVSHELL_BOOTSTRAP:-${ROOT}/deploy/docker/devshell-bootstrap.sh}"
PROFILE_DIR="${OPENSHELL_DEVSHELL_PROFILE_DIR:-${ROOT}/scripts/devshell.profiles}"
POLICY_FILE="${OPENSHELL_DEVSHELL_POLICY:-}"
DEVSHELL_PROVIDER="${OPENSHELL_DEVSHELL_TOOLCHAIN_PROVIDER:-openshell-dev-toolchains}"
PROVIDERS="${OPENSHELL_DEVSHELL_PROVIDERS-github codex claude ${DEVSHELL_PROVIDER}}"
REPO="${OPENSHELL_DEVSHELL_REPO:-}"

usage() {
  cat <<'USAGE'
Usage:
  scripts/devshell                  Create or connect to the dev sandbox
  scripts/devshell -- <command...>  Run a command in the dev sandbox
  scripts/devshell recreate         Delete and recreate the dev sandbox
  scripts/devshell delete           Delete the dev sandbox
  scripts/devshell policy           Print the optional policy override path
  scripts/devshell profiles         Print the dev provider profile directory

Environment:
  OPENSHELL_DEVSHELL_IMAGE       Sandbox image (default: openshell/ci:dev)
  OPENSHELL_DEVSHELL_REPO        GitHub repo slug or URL (default: origin remote)
  OPENSHELL_DEVSHELL_PROVIDERS   Provider names/types to attach
                                  (default: github codex claude openshell-dev-toolchains)
  OPENSHELL_DEVSHELL_POLICY      Optional policy file override (default: none)
  OPENSHELL_DEVSHELL_PROFILE_DIR Provider profiles to import for Providers v2
  OPENSHELL_DEVSHELL_BOOTSTRAP   Fallback bootstrap helper for images that do not include one
USAGE
}

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

openshell() {
  "$OPENSHELL_BIN" "$@"
}

normalize_repo() {
  local input=$1
  input="${input%.git}"
  case "$input" in
    https://github.com/*/*) input="${input#https://github.com/}" ;;
    http://github.com/*/*) input="${input#http://github.com/}" ;;
    git@github.com:*) input="${input#git@github.com:}" ;;
    ssh://git@github.com/*/*) input="${input#ssh://git@github.com/}" ;;
  esac
  printf '%s\n' "$input"
}

repo_slug() {
  local repo=$REPO
  if [[ -z "$repo" ]]; then
    repo="$(git -C "$ROOT" config --get remote.origin.url 2>/dev/null || true)"
  fi
  repo="$(normalize_repo "$repo")"
  [[ -n "$repo" ]] || repo="NVIDIA/OpenShell"
  [[ "$repo" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]] \
    || fail "OPENSHELL_DEVSHELL_REPO must be a GitHub owner/repo slug or URL, got '$repo'"
  printf '%s\n' "$repo"
}

provider_args() {
  local provider
  for provider in $PROVIDERS; do
    printf '%s\n' "--provider"
    printf '%s\n' "$provider"
  done
}

policy_args() {
  if [[ -n "$POLICY_FILE" ]]; then
    printf '%s\n' "--policy"
    printf '%s\n' "$POLICY_FILE"
  fi
}

profile_id_from_file() {
  sed -n -E 's/^id:[[:space:]]*"?([^"#]+)"?[[:space:]]*$/\1/p' "$1" | head -n 1
}

ensure_provider_profile() {
  local file=$1
  local id
  id="$(profile_id_from_file "$file")"
  [[ -n "$id" ]] || fail "provider profile '$file' is missing an id"
  if openshell provider profile export "$id" -o json >/dev/null 2>&1; then
    return
  fi
  openshell provider profile import -f "$file" >/dev/null
}

ensure_provider_profiles_v2() {
  local file
  for file in "$PROFILE_DIR"/*.yaml "$PROFILE_DIR"/*.yml "$PROFILE_DIR"/*.json; do
    [[ -f "$file" ]] || continue
    ensure_provider_profile "$file"
  done
  openshell settings set --global --key providers_v2_enabled --value true --yes >/dev/null
}

ensure_devshell_provider() {
  if openshell provider get "$DEVSHELL_PROVIDER" >/dev/null 2>&1; then
    return
  fi
  openshell provider create \
    --name "$DEVSHELL_PROVIDER" \
    --type "$DEVSHELL_PROVIDER" \
    --credential OPENSHELL_DEVSHELL_ACCESS=1 \
    >/dev/null
}

attach_devshell_provider() {
  openshell sandbox provider attach "$SANDBOX_NAME" "$DEVSHELL_PROVIDER" >/dev/null
}

quote_command() {
  local quoted=()
  local item q
  for item in "$@"; do
    printf -v q '%q' "$item"
    quoted+=("$q")
  done
  printf '%s\n' "${quoted[*]}"
}

base64_file() {
  base64 < "$1" | tr -d '\n'
}

bootstrap_command() {
  local repo=$1
  local command_string=$2
  local bootstrap_b64
  bootstrap_b64="$(base64_file "$BOOTSTRAP_FILE")"
  {
    printf 'set -euo pipefail\n'
    printf 'export OPENSHELL_DEVSHELL_REPO_SLUG=%q\n' "$repo"
    printf 'set -- %s\n' "$command_string"
    cat <<'EOF'
if command -v openshell-devshell-bootstrap >/dev/null 2>&1; then
  exec openshell-devshell-bootstrap "$@"
fi
mkdir -p /sandbox
EOF
    printf 'printf %%s %q | base64 -d > /sandbox/.openshell-devshell-bootstrap\n' "$bootstrap_b64"
    cat <<'EOF'
chmod +x /sandbox/.openshell-devshell-bootstrap
exec /sandbox/.openshell-devshell-bootstrap "$@"
EOF
  }
}

bash_script_arg() {
  local script=$1
  local encoded
  encoded="$(printf '%s' "$script" | base64 | tr -d '\n')"
  # shellcheck disable=SC2016
  printf 'eval "$(printf %%s %q | base64 -d)"\n' "$encoded"
}

run_in_sandbox() {
  local repo command_string script
  repo="$(repo_slug)"
  command_string="$(quote_command "$@")"
  script="$(bootstrap_command "$repo" "$command_string")"
  script="$(bash_script_arg "$script")"
  openshell sandbox exec -n "$SANDBOX_NAME" --workdir /sandbox --tty -- /bin/bash -lc "$script"
}

main() {
  [[ -x "$OPENSHELL_BIN" ]] || command -v "$OPENSHELL_BIN" >/dev/null 2>&1 \
    || fail "openshell binary not found: $OPENSHELL_BIN"
  [[ -z "$POLICY_FILE" || -f "$POLICY_FILE" ]] || fail "policy file not found: $POLICY_FILE"
  [[ -f "$BOOTSTRAP_FILE" ]] || fail "bootstrap helper not found: $BOOTSTRAP_FILE"
  [[ -d "$PROFILE_DIR" ]] || fail "provider profile directory not found: $PROFILE_DIR"

  local subcommand=connect
  if [[ $# -gt 0 ]]; then
    case "$1" in
      -h|--help|help)
        usage
        exit 0
        ;;
      connect|recreate|delete|policy|profiles)
        subcommand=$1
        shift
        ;;
      --)
        shift
        ;;
    esac
  fi
  if [[ $# -gt 0 && "$1" == "--" ]]; then
    shift
  fi

  case "$subcommand" in
    policy)
      if [[ -n "$POLICY_FILE" ]]; then
        printf '%s\n' "$POLICY_FILE"
      else
        printf 'no policy override configured; using Providers v2 profiles from %s\n' "$PROFILE_DIR"
      fi
      exit 0
      ;;
    profiles)
      printf '%s\n' "$PROFILE_DIR"
      exit 0
      ;;
    delete)
      openshell sandbox delete "$SANDBOX_NAME"
      exit $?
      ;;
  esac

  local command=(/bin/bash -l)
  if [[ $# -gt 0 ]]; then
    command=("$@")
  fi

  ensure_provider_profiles_v2
  ensure_devshell_provider

  if openshell sandbox get "$SANDBOX_NAME" >/dev/null 2>&1; then
    if [[ "$subcommand" == recreate ]]; then
      openshell sandbox delete "$SANDBOX_NAME"
    else
      attach_devshell_provider
      run_in_sandbox "${command[@]}"
      exit $?
    fi
  fi

  if [[ -z "${GITHUB_TOKEN:-}" && -z "${GH_TOKEN:-}" ]] && command -v gh >/dev/null 2>&1; then
    GH_TOKEN="$(gh auth token 2>/dev/null || true)"
    export GH_TOKEN
  fi

  local providers=()
  while IFS= read -r arg; do
    providers+=("$arg")
  done < <(provider_args)
  local policy=()
  while IFS= read -r arg; do
    policy+=("$arg")
  done < <(policy_args)

  local repo command_string script
  repo="$(repo_slug)"
  command_string="$(quote_command "${command[@]}")"
  script="$(bootstrap_command "$repo" "$command_string")"
  script="$(bash_script_arg "$script")"

  openshell sandbox create \
    --name "$SANDBOX_NAME" \
    --from "$SANDBOX_IMAGE" \
    "${policy[@]}" \
    "${providers[@]}" \
    --auto-providers \
    --tty \
    -- /bin/bash -lc "$script"
}

main "$@"
