#!/bin/bash
#Nifty: Install Percona Distribution for PostgreSQL

# shellcheck source=../../lib/universal/niftylib.sh
source <(curl -fSs https://nifty.sh/lib/universal/niftylib.sh)

require_root
require_os alma9 alma10

PGSQL_PASSWORD="$(random_string 16)"
if [ -f "/root/.pgsql" ]; then
	echo "A file under /root/.pgsql already exists! Exiting"
	exit 1
fi

with_umask 077 tee /root/.pgsql <<< "$PGSQL_PASSWORD" > /dev/null

ce "Retrieving list of available versions"
RETRIES=0
while :; do
  # Note that sort -rhu causes some versions to be lost, thus we use uniq
  readarray -t PG_VERSIONS <<< "$(curl -Ssf https://repo.percona.com/ | grep -oP 'ppg-\d+\/' | tr -dc '[:digit:]\n' | sort -rh | uniq)"
  [ "${#PG_VERSIONS[@]}" -gt "0" ] && break

  err "Failed to get repository index from https://repo.percona.com"
  [ "$RETRIES" -gt "2" ] && exit 1
  err "Retrying in 3 seconds..."
  RETRIES="$((RETRIES+1))"
  sleep 3
done

if ! is_interactive; then
  PG_VERSION="${PG_VERSIONS[0]}"
else
  echo "The following releases are available for installation: $(implode ", " "${PG_VERSIONS[@]}")"
  PG_VERSION="$(prompt_select "Which PostgreSQL release would you like to install?" "${PG_VERSIONS[@]}")"
fi

if is_interactive && prompt_confirm "Should PostgreSQL to listen on 0.0.0.0?"; then
  PG_BIND_ADDRESS="0.0.0.0"
else
  PG_BIND_ADDRESS="127.0.0.1"
fi

is_interactive && PG_LANGUAGE="$(prompt_select_num_value "Do you want to configure locales for Danish or English data?" "danish" "english")"
if [ -z "$PG_LANGUAGE" ]; then
  err "Please select the language to use for locale and fulltext searches using the PG_LANGUAGE environment variable. Valid options are "'da'" "'"en"'"."
  exit 1
fi

case "$PG_LANGUAGE" in
  danish)
    PG_ICU_LOCALE="da_DK"
    PG_FULLTEXT_LANGUAGE="danish"
  ;;
  english)
    PG_ICU_LOCALE="en_US"
    PG_FULLTEXT_LANGUAGE="english"
  ;;
  *)
    err "Invalid locale/fulltext language PG_LANGUAGE=\"$PG_LANGUAGE\"."
    exit 1
  ;;
esac

PG_CONFIGURE_BACKUP=0
if is_interactive && prompt_confirm "Do you want to configure backups using PGCloney?"; then
  PG_CONFIGURE_BACKUP=1
fi

ce "Updating system packages..."
dnf update -y

ce "Disabling PostgreSQL AppStream module"
dnf -qy module disable postgresql

ce "Installing EPEL"
dnf install epel-release yum-utils binutils -y

ce "Installing Percona repository"
rpm -Uvh https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release setup "ppg-$PG_VERSION"

ce "Installing PostgreSQL and Contrib"
export PERCONA_TELEMETRY_DISABLE=1
dnf -y install "percona-postgresql$PG_VERSION-server" "percona-postgresql$PG_VERSION-contrib"
if [ "$OS_VERSION" -lt 10 ]; then
  systemctl disable --now percona-telemetry-agent
fi

ce "Creating directory structure for data"
mkdir -p "/data/postgres/$PG_VERSION/data"

ce "Setting ownership"
chown -R postgres: "/data/postgres/$PG_VERSION"

ce "Adding PGDATA override to systemd"
if [ ! -d "/etc/systemd/system/postgresql-$PG_VERSION.service.d" ]; then
	mkdir "/etc/systemd/system/postgresql-$PG_VERSION.service.d"
fi

cat <<EOF > "/etc/systemd/system/postgresql-$PG_VERSION.service.d/override.conf"
[Service]
Environment=PGDATA=/data/postgres/$PG_VERSION/data
EOF

ce "Reloading systemd"
systemctl daemon-reload

ce "Initializing database"

INITDB_OPTIONS=(
  "--encoding=UTF-8"
  "--data-checksums"
  "--locale-provider=icu"
  "--icu-locale=$PG_ICU_LOCALE"
  "--text-search-config=$PG_FULLTEXT_LANGUAGE"
  "--set" "listen_addresses=$PG_BIND_ADDRESS"
  "--set" "shared_buffers=$(($(get_total_memory) / 4 / 1024 / 1024))MB"
  "--set" "effective_cache_size=$(($(get_total_memory) / 2 / 1024 / 1024))MB"
  "--set" "random_page_cost=1.1"
  "--set" "effective_io_concurrency=200"
  "--set" "wal_level=logical"
  "--set" "archive_mode=on"
  "--set" "archive_command=/bin/true"
  "--set" "shared_preload_libraries=pg_stat_statements"
  "--set" "log_connections=true"
  "--set" "log_disconnections=true"
  "--set" "log_duration=true"
  "--set" "log_statement=none"
  "--set" "log_min_duration_statement=250ms"
  "--set" "track_io_timing=true"
  "--set" "track_wal_io_timing=true"
  "--set" "lock_timeout=60s"
  "--set" "idle_in_transaction_session_timeout=5min"
)

export PGSETUP_INITDB_OPTIONS="${INITDB_OPTIONS[*]}"
"/usr/pgsql-$PG_VERSION/bin/postgresql-$PG_VERSION-setup" initdb

ce "Enabling and starting service"
systemctl enable --now "postgresql-$PG_VERSION"

ce "Giving the service a moment to start ... "
sleep 5

ce "Configuring host based authentication"
sed -i '/^# TYPE/,$d' "/data/postgres/$PG_VERSION/data/pg_hba.conf"

cat <<EOF >> "/data/postgres/$PG_VERSION/data/pg_hba.conf"
# By default we allow connections from everywhere to everyone
local   all             all                                  scram-sha-256
host    all             all             0.0.0.0/0            scram-sha-256
host    all             all             ::/0                 scram-sha-256

#local   replication     all                                     peer
#host    replication     all             127.0.0.1/32            scram-sha-256
#host    replication     all             ::1/128                 scram-sha-256
EOF

if [ "$PG_CONFIGURE_BACKUP" = 1 ]; then
  echo 'host    replication     all             127.0.0.1/32            scram-sha-256' >> "/data/postgres/$PG_VERSION/data/pg_hba.conf"
fi

ce "Setting the postgres password"
sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '$PGSQL_PASSWORD';"

ce "Restarting postgres for changes to take effect"
systemctl restart "postgresql-$PG_VERSION"

ce "Configuring pgpass and psql client"
export PGHOST=127.0.0.1
echo "export PGHOST=127.0.0.1" >> /root/.bashrc
export PGUSER=postgres
echo "export PGUSER=postgres" >> /root/.bashrc
with_umask 077 tee /root/.pgpass <<< "127.0.0.1:5432:*:postgres:$PGSQL_PASSWORD" > /dev/null

tee /root/.psqlrc > /dev/null <<EOF
\pset format aligned
\pset pager off
EOF

if is_interactive; then
  while :; do
    RESPONSE="$(prompt_select_num "Do you want to create a user?" "Create admin user" "Create normal user + database" "Done")"

    if [ "$RESPONSE" -eq "1" ]; then
      if [ -n "$ADMIN_PASSWORD" ]; then
        err "You have already created an admin user, dummy :)"
        continue
      fi

      ADMIN_PASSWORD="$(random_string 24)"
      psql -qc "CREATE USER admin WITH SUPERUSER CREATEROLE CREATEDB ENCRYPTED PASSWORD '$ADMIN_PASSWORD'"

      echo
      ce "Administrator user created"
      echo "Username: admin"
      echo "Password: $ADMIN_PASSWORD"
      with_umask 077 tee "/root/pgcredentials_admin.txt" <<< "User/DB: admin Password: $ADMIN_PASSWORD" > /dev/null
    fi

    if [ "$RESPONSE" -eq "2" ]; then
      NEW_USERNAME="$(prompt_string "Username")"
      NEW_PASSWORD="$(random_string 24)"
      psql -qc "CREATE DATABASE $NEW_USERNAME" > /dev/null
      psql -qc "CREATE USER $NEW_USERNAME WITH ENCRYPTED PASSWORD '$NEW_PASSWORD'"
      psql -qc "GRANT ALL PRIVILEGES ON DATABASE $NEW_USERNAME TO $NEW_USERNAME"
      psql -d "$NEW_USERNAME" -qc "GRANT ALL ON SCHEMA public TO $NEW_USERNAME"

      echo
      ce "Normal user and database created"
      echo "Database: $NEW_USERNAME"
      echo "Username: $NEW_USERNAME"
      echo "Password: $NEW_PASSWORD"

      with_umask 077 tee "/root/pgcredentials_$NEW_USERNAME.txt" <<< "User/DB: $NEW_USERNAME Password: $NEW_PASSWORD" > /dev/null
    fi

    echo
    if [ "$RESPONSE" -eq "3" ]; then
      break
    fi
  done
fi

if [ "$PG_CONFIGURE_BACKUP" = 1 ]; then
  ce "Configuring backup with PGCloney"
  mkdir -p /scripts/pgcloney
  chmod 700 /scripts/pgcloney
  wget -O /scripts/pgcloney/pgcloney.php https://nifty.sh/artifacts/scripts/pgcloney.php
  chmod 700 /scripts/pgcloney/pgcloney.php

  if [ ! -f "/scripts/pgcloney/credentials.json" ]; then
    ce "Registering with DBCloney API"
    /scripts/pgcloney/pgcloney.php
  fi
fi

ce "Installation complete!"
