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

# K8Studio Keycloak OIDC lab
#
# This script installs Keycloak into a Kubernetes cluster and configures a
# basic OIDC realm/client/user/group for testing K8Studio browser SSO.
#
# Requirements:
# - kubectl connected to your test cluster
# - Helm 3
# - Permission to install charts and create namespaces
#
# Usage:
#   ./k8studio-keycloak-oidc-lab.sh install
#   ./k8studio-keycloak-oidc-lab.sh configure
#   ./k8studio-keycloak-oidc-lab.sh port-forward
#   ./k8studio-keycloak-oidc-lab.sh uninstall

NAMESPACE="${NAMESPACE:-keycloak}"
RELEASE="${RELEASE:-keycloak}"
ADMIN_USER="${ADMIN_USER:-admin}"
ADMIN_PASSWORD="${ADMIN_PASSWORD:-ChangeMe123!}"
REALM="${REALM:-k8studio-auth}"
CLIENT_ID="${CLIENT_ID:-k8studio}"
TEST_USER="${TEST_USER:-alice}"
TEST_USER_EMAIL="${TEST_USER_EMAIL:-alice@example.com}"
TEST_USER_PASSWORD="${TEST_USER_PASSWORD:-Password123!}"
K8S_GROUP="${K8S_GROUP:-k8studio-admins}"
LOCAL_PORT="${LOCAL_PORT:-8080}"

usage() {
  cat <<USAGE
K8Studio Keycloak OIDC lab

Commands:
  install        Install Keycloak with Helm
  configure      Create realm, client, user, group, and group mapper
  port-forward   Open Keycloak locally at http://localhost:${LOCAL_PORT}
  uninstall      Remove Keycloak and the namespace

Environment overrides:
  NAMESPACE=${NAMESPACE}
  RELEASE=${RELEASE}
  ADMIN_USER=${ADMIN_USER}
  ADMIN_PASSWORD=${ADMIN_PASSWORD}
  REALM=${REALM}
  CLIENT_ID=${CLIENT_ID}
  TEST_USER=${TEST_USER}
  TEST_USER_EMAIL=${TEST_USER_EMAIL}
  TEST_USER_PASSWORD=${TEST_USER_PASSWORD}
  K8S_GROUP=${K8S_GROUP}
  LOCAL_PORT=${LOCAL_PORT}

Example:
  ADMIN_PASSWORD='Use-A-Real-Password' ./k8studio-keycloak-oidc-lab.sh install
USAGE
}

require_command() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "Missing required command: $1" >&2
    exit 1
  fi
}

keycloak_pod() {
  kubectl get pods -n "${NAMESPACE}" \
    -l "app.kubernetes.io/instance=${RELEASE},app.kubernetes.io/name=keycloak" \
    -o jsonpath='{.items[0].metadata.name}'
}

install_keycloak() {
  require_command kubectl
  require_command helm

  kubectl create namespace "${NAMESPACE}" --dry-run=client -o yaml | kubectl apply -f -

  helm repo add bitnami https://charts.bitnami.com/bitnami
  helm repo update

  helm upgrade --install "${RELEASE}" bitnami/keycloak \
    --namespace "${NAMESPACE}" \
    --set "auth.adminUser=${ADMIN_USER}" \
    --set "auth.adminPassword=${ADMIN_PASSWORD}"

  kubectl rollout status "statefulset/${RELEASE}" -n "${NAMESPACE}" --timeout=10m

  cat <<DONE

Keycloak is installed.

Admin console:
  ./k8studio-keycloak-oidc-lab.sh port-forward
  http://localhost:${LOCAL_PORT}/admin

Admin login:
  user:     ${ADMIN_USER}
  password: ${ADMIN_PASSWORD}

Next:
  ./k8studio-keycloak-oidc-lab.sh configure
DONE
}

configure_keycloak() {
  require_command kubectl

  local pod
  pod="$(keycloak_pod)"

  if [[ -z "${pod}" ]]; then
    echo "Could not find a Keycloak pod in namespace ${NAMESPACE}" >&2
    exit 1
  fi

  kubectl exec -n "${NAMESPACE}" "${pod}" -- bash -lc "
    set -euo pipefail
    KCADM=/opt/bitnami/keycloak/bin/kcadm.sh

    \"\$KCADM\" config credentials \
      --server http://localhost:8080/ \
      --realm master \
      --user '${ADMIN_USER}' \
      --password '${ADMIN_PASSWORD}'

    \"\$KCADM\" get realms/'${REALM}' >/dev/null 2>&1 || \
      \"\$KCADM\" create realms \
        -s realm='${REALM}' \
        -s enabled=true

    CLIENT_UUID=\$(\"\$KCADM\" get clients -r '${REALM}' -q clientId='${CLIENT_ID}' --fields id --format csv --noquotes | tail -n 1 || true)

    if [ -z \"\$CLIENT_UUID\" ]; then
      \"\$KCADM\" create clients -r '${REALM}' \
        -s clientId='${CLIENT_ID}' \
        -s enabled=true \
        -s publicClient=true \
        -s standardFlowEnabled=true \
        -s directAccessGrantsEnabled=true \
        -s 'redirectUris=[\"http://localhost:*\",\"http://127.0.0.1:*\"]' \
        -s 'webOrigins=[\"http://localhost:*\",\"http://127.0.0.1:*\"]'

      CLIENT_UUID=\$(\"\$KCADM\" get clients -r '${REALM}' -q clientId='${CLIENT_ID}' --fields id --format csv --noquotes | tail -n 1)
    fi

    \"\$KCADM\" get groups -r '${REALM}' | grep -q '\"name\" : \"${K8S_GROUP}\"' || \
      \"\$KCADM\" create groups -r '${REALM}' -s name='${K8S_GROUP}'

    USER_ID=\$(\"\$KCADM\" get users -r '${REALM}' -q username='${TEST_USER}' --fields id --format csv --noquotes | tail -n 1 || true)

    if [ -z \"\$USER_ID\" ]; then
      \"\$KCADM\" create users -r '${REALM}' \
        -s username='${TEST_USER}' \
        -s email='${TEST_USER_EMAIL}' \
        -s enabled=true \
        -s emailVerified=true

      USER_ID=\$(\"\$KCADM\" get users -r '${REALM}' -q username='${TEST_USER}' --fields id --format csv --noquotes | tail -n 1)
    fi

    \"\$KCADM\" set-password -r '${REALM}' \
      --userid \"\$USER_ID\" \
      --new-password '${TEST_USER_PASSWORD}' \
      --temporary=false

    GROUP_ID=\$(\"\$KCADM\" get groups -r '${REALM}' --fields id,name --format csv --noquotes | awk -F, '\$2 == \"${K8S_GROUP}\" { print \$1; exit }')
    \"\$KCADM\" update users/\"\$USER_ID\"/groups/\"\$GROUP_ID\" -r '${REALM}' -s realm='${REALM}' -s userId=\"\$USER_ID\" -s groupId=\"\$GROUP_ID\" -n || true

    \"\$KCADM\" create clients/\"\$CLIENT_UUID\"/protocol-mappers/models -r '${REALM}' \
      -s name=groups \
      -s protocol=openid-connect \
      -s protocolMapper=oidc-group-membership-mapper \
      -s 'config.\"claim.name\"=groups' \
      -s 'config.\"full.path\"=false' \
      -s 'config.\"id.token.claim\"=true' \
      -s 'config.\"access.token.claim\"=true' \
      -s 'config.\"userinfo.token.claim\"=true' >/dev/null 2>&1 || true
  "

  cat <<DONE

Keycloak OIDC lab is configured.

Realm:
  ${REALM}

Client:
  ${CLIENT_ID}

Test user:
  username: ${TEST_USER}
  password: ${TEST_USER_PASSWORD}
  group:    ${K8S_GROUP}

Issuer URL after port-forward:
  http://localhost:${LOCAL_PORT}/realms/${REALM}

Admin console:
  ./k8studio-keycloak-oidc-lab.sh port-forward
  http://localhost:${LOCAL_PORT}/admin
DONE
}

port_forward() {
  require_command kubectl
  echo "Opening Keycloak at http://localhost:${LOCAL_PORT}"
  echo "Press Ctrl-C to stop the port-forward."
  kubectl port-forward -n "${NAMESPACE}" "svc/${RELEASE}" "${LOCAL_PORT}:80"
}

uninstall_keycloak() {
  require_command kubectl
  require_command helm

  helm uninstall "${RELEASE}" -n "${NAMESPACE}" || true
  kubectl delete namespace "${NAMESPACE}" --ignore-not-found
}

case "${1:-}" in
  install)
    install_keycloak
    ;;
  configure)
    configure_keycloak
    ;;
  port-forward)
    port_forward
    ;;
  uninstall|destroy|delete)
    uninstall_keycloak
    ;;
  -h|--help|help|"")
    usage
    ;;
  *)
    echo "Unknown command: $1" >&2
    usage
    exit 1
    ;;
esac
