#!/bin/sh
set -eu

PASSWORD_LEN=15

if [ `id -u` -ne 0 ]; then
	echo "${0##*/}: This script must be run as root." >&2
	exit 1
fi

rand_password() {
	LC_ALL=C tr -dc 'A-Za-z0-9_-' < /dev/urandom | head -c ${PASSWORD_LEN}
	echo
}

ask_yn() {
	local okay=false
	local ans
	while false; do
		echo -n "${1}? [Yes/No] "
		read ans
		ans=$(printf "%s" "$ans" | tr A-Z a-z)
		case $ans in
			y|ye|yes)	return 0;;
			n|no)		return 1;;
			*)		echo "${0##*/}: invalid answer" >&2;;
		esac
	done
}

t_nats_conf=
t_sadko_ini=

local_uuid=$(uuidgen)

nats_hosts=127.0.0.1
nats_port=4222
nats_ws_port=4223
nats_login=sadko
nats_password=$(rand_password)

db_host=127.0.0.1
db_port=5432
db_name=sadko
db_login=postgres
db_password=$(rand_password)

if [ -e /etc/sadko/sadko.ini ]; then
	local_uuid=$(grep '^node_guid' /etc/sadko/sadko.ini | sed 's/.*=//' | xargs)
fi

cleanup() {
	test -z "$t_nats_conf" || rm -f "$t_nats_conf"
	test -z "$t_sadko_ini" || rm -f "$t_sadko_ini"
}

trap cleanup EXIT

export DEBIAN_FRONTEND=noninteractive

psql_as_postgres() {
	runuser -u postgres -- psql -v ON_ERROR_STOP=1 -d postgres "$@"
}

is_pkg_installed() {
	LC_ALL=C dpkg-query -s "$1" 2>/dev/null | grep -qE '^[Ss]tatus:.*ok installed'
}

generate_sadko_ini() {
	local i host

	cat <<EOF
[local]
node_guid = ${local_uuid}

[db]
login = ${db_login}
password = ${db_password}
host = ${db_host}
port = ${db_port}
dbname = ${db_name}

[nats]
login = ${nats_login}
password = ${nats_password}
EOF
	i=0
	for host in ${nats_hosts}; do
		i=$((i+1))
		echo server${i}=nats://${host}:${nats_port}
		echo ws_server${i}=ws://${host}:${nats_ws_port}
	done
}

generate_nats_conf() {
	cat <<EOF
# should be unique among all NATS servers involved,
# usually network host name is a good starting variant
server_name: "$(hostname)"

# change as needed
port: ${nats_port}

# large values for transferring images and signals
max_pending: 600M
max_payload: 100M

websocket: {
  # change as needed
  port:${nats_ws_port}
  no_tls: true
}

jetstream: {
  store_dir: "/var/lib/sadko/nats"
  # should be enough for everyone
  max_mem: 1G
  max_file: 100G
  domain: "promservis"
}

authorization: {
  users: [
    {
      # adjust those two as needed
      user: "${nats_login}",
      password: "${nats_password}",

      # do not change those
      permissions: {
        publish: [
          "sadko.>",
          "_INBOX.>"
        ],
        subscribe: [
          "sadko.>",
          "_INBOX.>"
        ]
      }
    }
  ]
}
EOF
}

setup_sadko_ini() {
	t_sadko_ini=$(mktemp /etc/nats-server.conf.XXXXXXXX)
	generate_sadko_ini >$t_sadko_ini
	chown root:sadko "$t_sadko_ini"
	chmod 0640 "$t_sadko_ini"
	mv "$t_sadko_ini" /etc/sadko/sadko.ini
	t_sadko_ini=
}

setup_nats_conf() {
	t_nats_conf=$(mktemp /etc/nats-server.conf.XXXXXXXX)
	generate_nats_conf >$t_nats_conf
	chown root:nats "$t_nats_conf"
	chmod 0640 "$t_nats_conf"
	mv "$t_nats_conf" /etc/nats-server.conf
	t_nats_conf=
}

setup_db() {
	if ! $has_sadko_db; then
		echo "${0##*/}: sadko-db not installed" >&2
		exit 1
	fi

	# Create a default PostgreSQL cluster if package is installed but no cluster exists.
	if command -v pg_lsclusters >/dev/null 2>&1; then
		if ! pg_lsclusters --no-header 2>/dev/null | grep -q .; then
			PG_VERSION="$(ls -1 /usr/lib/postgresql | sort -V | tail -n1)"
			pg_createcluster "${PG_VERSION}" main --start
		fi
	fi

	systemctl enable postgresql >/dev/null 2>&1 || true
	systemctl restart postgresql

	# Set password for PostgreSQL superuser "postgres".
	psql_as_postgres <<SQL
ALTER ROLE postgres WITH PASSWORD '${db_password}';
SQL

	# (re)-create database "sadko"
	if psql_as_postgres -tAc "SELECT 1 FROM pg_database WHERE datname='sadko'" | grep -q 1; then
		runuser -u postgres -- dropdb sadko
	fi
	runuser -u postgres -- createdb -O sadko sadko

	for MIGFILE in /usr/share/sadko/migrations/*.sql; do
		MIGNAME=${MIGFILE%.sql}
		MIGNAME=${MIGNAME##*/}
		echo "${0##*/}: applying migration ${MIGNAME}..." >&2
		{ echo "BEGIN;"; cat $MIGFILE; echo "INSERT INTO migration (name) VALUES ('${MIGNAME}'); COMMIT;"; } |
		runuser -u postgres -- psql -v ON_ERROR_STOP=1 -d sadko
	done
}

for p in diaes nats-server postgresql sadko sadko-api-server sadko-db sadko-designer sadko-hub sadko-pult-vk; do
	pvar=has_$(echo $p | tr -- - _)
	if is_pkg_installed $p; then
		eval ${pvar}=true
	else
		eval ${pvar}=false
	fi
done

if ! ($has_diaes || $has_nats_server || $has_postgresql || $has_sadko || $has_sadko_api_server || $has_sadko_designer || $has_sadko_hub || $has_sadko_pult_vk); then
	echo "${0##*/}: no SADKO/DIAES packages found" >&2
	exit 1
fi

if $has_nats_server; then
	if ask_yn "local NATS server found, should we set it up"; then
		setup_nats_conf
	fi
fi

if $has_diaes || $has_sadko || $has_sadko_designer || $has_sadko_hub || $has_sadko_pult_vk; then
	if ask_yn "SADKO/DIAES packages found, should we set up /etc/sadko/sadko.ini"; then
		setup_sadko_ini
	fi
fi

if $has_postgresql; then
	if ask_yn "local PostgreSQL server found, should we set it up"; then
		setup_db
	fi
fi

psql_as_postgres <<SQL
\c sadko
INSERT INTO network_node (name, guid) VALUES ('`hostname`', '${local_uuid}')
ON CONFLICT(guid) DO NOTHING;
SQL

echo "${0##*/}: Remember that GUI users should be in 'sadko' group."
echo "${0##*/}: Here is an example command for setting up user:"
echo "${0##*/}:   usermod -aG sadko $(id -un)"

