#!/bin/bash
set -eu
### --help Info: инициализация конфигурации и данных контейнера.
### --help Usage: /opt/bin/eva_init.sh
### --help Example: /opt/bin/eva_init.sh
. /opt/fox_utils/crab_sys.sh

# Container environment
declare EVA_DEPLOY_TYPE

# sys::arg_parse "$@"


# Init /mnt/shared/config/CONFIG
if [[ ! -f /mnt/shared/config/CONFIG ]]; then
	case "$EVA_DEPLOY_TYPE" in
	box|box-lxc|cloud-lxc)
		cp /opt/bin/templates/CONFIG /mnt/shared/config/CONFIG.$$
		/opt/fox_utils/crab_conf set EVA_DEPLOY_TYPE "$EVA_DEPLOY_TYPE" \
			/mnt/shared/config/CONFIG.$$
		mv /mnt/shared/config/CONFIG.$$ /mnt/shared/config/CONFIG
		;;
	*)
		echo "Unsupported EVA_DEPLOY_TYPE = $EVA_DEPLOY_TYPE" >&2
		;;
	esac
else
	/opt/fox_utils/crab_conf set EVA_DEPLOY_TYPE "$EVA_DEPLOY_TYPE" \
		/mnt/shared/config/CONFIG
fi


# Set CONFIG by container env,
# Пока только для single варианта,
# TODO Кластер по месту(т.к. конфиг в кластере общий и возможно RO):
#   EVA_DEPLOY_TYPE = cluster-master|cluster-control|*-master|*-control
case "$EVA_DEPLOY_TYPE" in
box|box-lxc|cloud-lxc)
	for container_var in "${!EVA_CONFIG__@}"; do
		config_var="${container_var#EVA_CONFIG__}"
		/opt/fox_utils/crab_conf set "$config_var" "${!container_var}" \
			/mnt/shared/config/CONFIG
	done
	;;
esac


declare DOMAIN
declare EMAIL_HOST_ADDR
declare EMAIL_PORT
declare EMAIL_USER
declare EMAIL_LOGIN
declare EMAIL_PASSWORD
declare EMAIL_USE_SSL
declare DNS_SERVER1
declare DNS_SERVER2
declare EVA_DEPLOY_TYPE SLA

declare POSTGRESQL_ENABLED REDIS_SERVER_ENABLED MEMORY_LIMIT_GB
declare MANUAL_CONFIGURATION=
source /opt/CONFIG


set_data_location() {
	local hostname dir loc dir_loc

	hostname="$(hostname)"

	case "$EVA_DEPLOY_TYPE" in
	box|box-lxc|cloud-lxc)
		# Single container используем /mnt/shared вместо /mnt/shared/hosts/$hostname
		loc=/mnt/shared
		;;
	*)
		# Многоконтейнерый деплой,
		#   используем /mnt/shared/hosts/$hostname для приватных персистентных данных
		# TODO уточнить типы
		loc="/mnt/shared/hosts/$hostname"
		if [[ ! -d $loc ]]; then
			mkdir "$loc"
		fi
		;;
	esac

	for dir in root var/log var/lib/postgresql; do
		if [[ $loc == /mnt/shared ]]; then
			# Сохраняем в корень для удобства.
			dir_loc="$loc/${dir##*/}"
		else
			dir_loc="$loc/$dir"
		fi
		# инициализация из скелета
		if [[ ! -d $dir_loc ]]; then
			rsync -a "/skelet/$dir/" "$dir_loc"
		fi
		# Правим линк в /mnt/tmp
		ln -sf --no-target-directory "$dir_loc" "/mnt/tmp/$dir"
	done
	# patch mnt/shared from skelet, absent dir only
	for dir in /skelet/config/* /skelet/config/etc/*; do
		dir="${dir#/skelet/config/}"
		if [[ -d /skelet/config/$dir && ! -d /mnt/shared/config/$dir ]]; then
			echo "Init absent conf dir /mnt/shared/config/$dir from /skelet/config/$dir" >&2
			rsync -a "/skelet/config/$dir/" "/mnt/shared/config/$dir"
		fi
	done
	# Кладем rw-данные из skelet в tmp
	# mkdir -p /mnt/tmp/etc/ssl/certs/
	# cp -a /skelet/etc/ssl/certs/ca-certificates.crt /mnt/tmp/etc/ssl/certs/ca-certificates.crt
	# mkdir -p /mnt/tmp/usr/local/lib/python3.8/dist-packages/certifi/
	# cp -a /skelet/usr/local/lib/python3.8/dist-packages/certifi/cacert.pem \
	#	/mnt/tmp/usr/local/lib/python3.8/dist-packages/certifi/cacert.pem
	# recreate apps tmp dirs
	mkdir -p /var/tmp/eva-app /var/tmp/eva-converter
	mkdir -p /mnt/shared/tmp/rdisk/{sessions,tokens}
	mkdir -p /mnt/shared/mail
	return 0
}


check_config(){
	echo "Проверяем файл конфигурации на наличие ошибок..."
	# DOMAIN
	if [[ "$DOMAIN" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Вы ввели в опцию DOMAIN ip адрес, нужно ввести доменное имя"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно /opt/bin/eva_configure"
		return 1
	fi
	if ! python3 -c \
		"import validators; exit(0) if validators.domain('${DOMAIN}') else exit(1)"; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Введите в опцию DOMAIN корректное доменное имя. Не вводите префикс https://"
		echo "Пример: eva.example.com или my-eva-domain.ru"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно."
		return 1
	fi
	if ! python3 -c \
		"import validators; exit(0) if validators.email('${ADMIN_EMAIL}') else exit(1)"; then
		echo "Ошибка в файле конфигурации /opt/CONFIG!"
		echo "Введите в опцию ADMIN_EMAIL корректный email администратора."
		echo "Пример: admin@example.com"
		echo "Отредактируйте файл /opt/CONFIG и запустите повторно."
		return 1
	fi
	return 0
}


configure_email_server(){
	# TODO: единообразный конфиг
	/opt/fox_utils/crab_conf set SMTP_SERVER "$EMAIL_HOST_ADDR" /opt/eva-app/custom/config.py
	sed "s/SMTP_PORT.*/SMTP_PORT=${EMAIL_PORT}/g" -i /opt/eva-app/custom/config.py

	/opt/fox_utils/crab_conf set EMAIL_HOST_ADDR "$EMAIL_HOST_ADDR" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_PORT "$EMAIL_PORT" /opt/eva-app/custom/config.py
	# crab_conf устанавливает значение с кавычками, уберем для python, чтобы был int
	sed "s/EMAIL_PORT.*/EMAIL_PORT=${EMAIL_PORT}/g" -i /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_USER "$EMAIL_USER" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_LOGIN "$EMAIL_LOGIN" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_PASSWORD "$EMAIL_PASSWORD" /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EMAIL_USE_SSL True /opt/eva-app/custom/config.py

	if [ "$EMAIL_USE_SSL" = "1" ]; then
		sed 's/EMAIL_USE_SSL.*/EMAIL_USE_SSL=True/g' -i /opt/eva-app/custom/config.py
	elif [ "$EMAIL_USE_SSL" = "0" ]; then
		sed 's/EMAIL_USE_SSL.*/EMAIL_USE_SSL=False/g' -i /opt/eva-app/custom/config.py
	else
		echo "ERROR! Опция EMAIL_USE_SSL должна быть 1 или 0"
	fi

	return 0
}


configure_resolv_conf(){
	# может использовать файл образа и перезатирать, только если указан.
	if [ "${EVA_DEPLOY_TYPE}" != "box-lxc" -a "${EVA_DEPLOY_TYPE}" != "cloud-lxc" ]; then
		# Только для деплоя lxc
		# Деплой докера возьмет DNS-сервера с хоста
		return 0
	fi
	if [[ ${DNS_SERVER1:-} ]]; then
		echo "options rotate" > /etc/resolv.conf
		echo "nameserver ${DNS_SERVER1:-8.8.8.8}" >> /etc/resolv.conf
		if [ -n "${DNS_SERVER2:-}" ]; then
			echo "nameserver ${DNS_SERVER2}" >> /etc/resolv.conf
		fi
	fi
	return 0
}


configure_eva_app() {
	# WHATSAPP_MESSENGER_URL = 'https://whatsapp.evacrm.ru'
	# WHATSAPP_PROXY_URL = 'http://localhost:8080'
	# fixme: crab_conf set True and False as str!!!
	/opt/fox_utils/crab_conf set IS_BOX_VERSION True /opt/eva-app/custom/config.py
	/opt/fox_utils/crab_conf set EVA_ACCOUNT_USE False /opt/eva-app/custom/config.py
	# Hack custom-шаблона
	cat /opt/eva-app/vassals/soketio.ini > /mnt/shared/config/eva-app/vassals/soketio.ini
	/opt/fox_utils/crab_conf set CONVERTER_PLANTUML_URL "http://127.0.0.1:8083/plantuml/" \
		/opt/eva-app/custom/config.py
	return 0
}


configure_wsgidav() {
	local account_auth_url org_name
	account_auth_url="$(
	sed -E "s/^AUTH_SERVER_URL\s*=\s*[\"'](.*)[\"']\s*$/\1/;t;d" /opt/eva-app/custom/config.py)"
	org_name="$(sed -E "s/^ORG_NAME\s*=\s*[\"'](.*)[\"']\s*$/\1/;t;d" /opt/eva-app/custom/config.py)"
	# fixme в облаке не заполнен custom/config.py, а /opt/eva-app/custom/org_name depricated
	if [[ ! "$org_name" && -f /opt/eva-app/custom/org_name ]]; then
		org_name="$(cat /opt/eva-app/custom/org_name)"
		# fixme mv to configure_crm
		/opt/fox_utils/crab_conf set ORG_NAME "$org_name" /opt/eva-app/custom/config.py
	fi
	if [[ ! "$org_name" ]]; then
		# Fallback, до регистрации, org_name может не быть.
		org_name="$(hostname)"
		echo "Warning! Use hostname($org_name) as org_name" >&2
	fi
	if [ -z "$account_auth_url" ]; then
		account_auth_url="https://account.evateam.ru"
	fi
	sed -E "s|(^\s{4}org_name: )(.*)|\1$org_name|; \
		s|(^\s{4}endpoint: )(.*)|\1\"$account_auth_url\"|;" \
		-i /mnt/shared/config/wsgidav/wsgidav.yaml
	return 0
}


configure_rdisk() {
	/opt/fox_utils/crab_conf set CONVERTER_URL "http://127.0.0.1:8083/converter/" \
		/opt/rdisk/rdisk/custom/config.py
	return 0
}


configure_convertor() {
	# Т.к. /root/ - персистентный и сам не обновляется, то скопируем скрипты в профиль здесь.
	mkdir -p /root/.config/libreoffice/4/user/basic/
	rsync -a --delete /opt/eva-converter/libreoffice_scripts/ /root/.config/libreoffice/4/user/basic/
	return 0
}


fix_jwt_keys() {
	# Изначально ключи приходят со сборщика, нам нужно их заменить своими кастомными.
	# rm -f /opt/account/jwt_rsa{,.pub,.pub.orig}
	# if [[ ! -f /opt/account/custom/jwt_rsa ]]; then
	# 	(
	# 		cd /opt/account
	# 		python3 manage.py generate_rsa_keypair
	# 	)
	# 	mv /opt/account/jwt_rsa{,.pub} /opt/account/custom/
	# fi
	# ln -s custom/jwt_rsa /opt/account/
	# ln -s custom/jwt_rsa.pub /opt/account/

	# skip strongbash010
	rm -f /opt/eva-app/tmp/jwt_rsa{,.pub,.pub.orig}
	if [[ ! -f /opt/eva-app/custom/jwt_rsa ]]; then
		(
			cd /opt/eva-app
			python3 manage.py generate_rsa_keypair
		)
		mv /opt/eva-app/tmp/jwt_rsa{,.pub} /opt/eva-app/custom/
	fi
	# Ссылки абсолютные, т.к. многоуровневые.
	ln -s /opt/eva-app/custom/jwt_rsa /opt/eva-app/tmp/
	# Здесь нужен открытый ключ аккаунта.
	if [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		ln -s /opt/eva-app/custom/jwt_rsa.account.pub /opt/eva-app/tmp/jwt_rsa.pub
	else
		ln -s /opt/eva-app/custom/jwt_rsa.pub /opt/eva-app/tmp/jwt_rsa.pub
	fi
	# Для работы приглашений
	# /opt/fox_utils/crab_conf set VM_TYPE devel /opt/account/custom/config.py
	# /opt/fox_utils/crab_conf set CRM_PUB_KEY "" /opt/account/custom/config.py
	# local key
	# key="$(sed ':a;N;$!ba;s/\n/\\\\n/g' </opt/eva-app/custom/jwt_rsa.pub)"
	# sed "s#CRM_PUB_KEY.*#CRM_PUB_KEY=\"$key\"#g" -i /opt/account/custom/config.py
	return 0
}


gen_crypt_keys(){
	local key iv
	if grep -q "SESSION_CRYPT_KEY" /opt/eva-app/custom/config.py; then
		sed -i 's/SESSION_CRYPT_KEY/EVA_INSTANCE_KEY/g' /opt/eva-app/custom/config.py
	fi
	if ! grep -q "EVA_INSTANCE_KEY" /opt/eva-app/custom/config.py; then
		key="$(openssl rand -hex 32)"
		iv="$(openssl rand -hex 16)"
		/opt/fox_utils/crab_conf set EVA_INSTANCE_KEY "AES:${iv}:${key}" \
			/opt/eva-app/custom/config.py
	fi
	return 0
}


do_autogen() {
	(
		cd /opt/eva-app
		python3 manage.py autogen
	)
	return 0
}


sync_custom_skelet() {
	# TODO: Check!
	if [ -d /mnt/shared/config/os_skelet ]; then
		# Init skelet from /mnt/shared/config/os_skelet
		/opt/fox_utils/crab_skelet_init /mnt/shared/config/os_skelet/ /
	fi
	return 0
}


main() {
	set_data_location
	sync_custom_skelet
	gen_crypt_keys

	if [[ $MANUAL_CONFIGURATION ]]; then
		echo "MANUAL_CONFIGURATION in /opt/CONFIG, skip auto config" >&2
	elif [[ $EVA_DEPLOY_TYPE = cloud* ]]; then
		# TODO: ??? Надо ли какую-то доп настройку под облако?
		# install -d /opt/eva-app/custom
		# touch /opt/eva-app/custom/config.py
		# # ??
		# echo evateam.ru > /opt/eva-app/custom/cloud_name
		if [[ ${SLA:-} ]]; then
			# TODO: выпилить fox_acrm
			# TODO: /opt/fox_acrm/deploy/provision.py - не заточен под коробку.
			echo "configure SLA $SLA" >&2
			/opt/fox_acrm/deploy/provision.py --sla "$SLA" --redis --postgres --uwsgi
			# Чтобы постоянные синки не клали ноду отключаем их у pg в облаке.
			echo "fsync = 0" >> /etc/postgresql/13/main/postgresql.conf
		fi
		configure_wsgidav
	elif [[ $EVA_DEPLOY_TYPE = box* ]]; then
		check_config
		/opt/fox_acrm/deploy/provision.py --memory-limit-gb "${MEMORY_LIMIT_GB:-8}" \
			--redis --postgres --uwsgi
		/opt/bin/_nginx_configure
		configure_email_server
		configure_resolv_conf
		configure_eva_app
		configure_wsgidav
		configure_rdisk
		configure_convertor
	else
		echo "Unsupported EVA_DEPLOY_TYPE=$EVA_DEPLOY_TYPE in /opt/CONFIG" >&2
		return 1
	fi
	# fixme зачем-то manage.py(автогену, keygen) нужны редис и постгрес
	#   у кубера будут проблемы со стартом, если БД будет не доступна.
	if [ "${REDIS_SERVER_ENABLED:-TRUE}" = 'TRUE' ]; then
		/etc/init.d/redis-server start
	fi
	if [ "${POSTGRESQL_ENABLED:-TRUE}" = 'TRUE' ]; then
		/etc/init.d/postgresql start
	fi
	do_autogen
	fix_jwt_keys
	return 0
}


main
exit 0
