#!/bin/bash

# exit when any step fails
set -euo pipefail

# :)
MY_NAME_IS_JAKE_JARVIS="false"

# can't say you weren't warned
if [ "$MY_NAME_IS_JAKE_JARVIS" != "pinky promise" ]; then
  echo "🚨 LISTEN UP!!!! YOU PROBABLY WANT THIS SCRIPT INSTEAD:"
  echo "https://github.com/jakejarvis/mastodon-installer/blob/main/install.sh"
  exit 69
fi

# initialize path (and silence warnings about things not existing yet because that's why we're running the installer...)
. "$(dirname "$(realpath "$0")")"/../init.sh >/dev/null 2>&1

# check for existing installation
if [ -d "$APP_ROOT" ]; then
  echo "⚠️ $APP_ROOT already exists. Are you sure Mastodon isn't already installed?"
  exit 255
fi

# ask for required info up-front
read -p "Server FQDN? " MASTODON_DOMAIN
read -p "Public domain? (the second part of usernames, usually the same) " MASTODON_USERNAME_DOMAIN
read -p "Admin username? " MASTODON_ADMIN_USERNAME
read -p "Admin email? " MASTODON_ADMIN_EMAIL
read -p "Linode bucket name? " LINODE_BUCKET_NAME

# leave our mark
INSTALLER_WUZ_HERE="# Generated by mastodon-installer @ $(date)"

# set FQDN (especially necessary for sendmail)
echo -e "\n$INSTALLER_WUZ_HERE
127.0.0.1  localhost $MASTODON_DOMAIN
::1  localhost $MASTODON_DOMAIN" | sudo tee -a /etc/hosts >/dev/null
sudo hostnamectl set-hostname "$MASTODON_DOMAIN"

# create non-root mastodon user
sudo adduser --disabled-login --gecos "Mastodon" mastodon

# install latest ubuntu updates
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt upgrade -y
sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
  curl \
  wget \
  gnupg \
  apt-transport-https \
  lsb-release \
  ca-certificates

# add nodesource apt repository
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource.gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/nodesource-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nodesource-archive-keyring.gpg] https://deb.nodesource.com/node_16.x $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/nodesource.list >/dev/null

# add official postgresql apt repository
curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo gpg --dearmor -o /usr/share/keyrings/postgresql-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/postgresql-archive-keyring.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list >/dev/null

# add official redis apt repository
curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/redis.list >/dev/null

# add official nginx apt repository
curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /usr/share/keyrings/nginx-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] http://nginx.org/packages/ubuntu/ $(lsb_release -cs) nginx" | sudo tee /etc/apt/sources.list.d/nginx.list >/dev/null

# install prerequisites:
# https://docs.joinmastodon.org/admin/install/#system-packages
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
  git-core \
  g++ \
  libpq-dev \
  libxml2-dev \
  libxslt1-dev \
  imagemagick \
  nodejs \
  redis-server \
  redis-tools \
  postgresql \
  postgresql-contrib \
  libidn11-dev \
  libicu-dev \
  libreadline6-dev \
  autoconf \
  bison \
  build-essential \
  ffmpeg \
  file \
  gcc \
  libffi-dev \
  libgdbm-dev \
  libjemalloc-dev \
  libncurses5-dev \
  libprotobuf-dev \
  libssl-dev \
  libyaml-dev \
  pkg-config \
  protobuf-compiler \
  zlib1g-dev \
  nginx \
  python3 \
  python3-venv \
  libaugeas0

# setup yarn
sudo npm install --global yarn
sudo corepack enable

# install rbenv & ruby-build
as_mastodon git clone https://github.com/rbenv/rbenv.git "$RBENV_ROOT"
as_mastodon git clone https://github.com/rbenv/ruby-build.git "$RBENV_ROOT/plugins/ruby-build"
eval "$("$RBENV_ROOT"/bin/rbenv init -)"

# clone vanilla Mastodon & checkout latest version:
as_mastodon git clone https://github.com/mastodon/mastodon.git "$APP_ROOT" && cd "$APP_ROOT"
as_mastodon git checkout "$(as_mastodon git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)"
# clone glitch-soc & checkout latest commit:
# as_mastodon git clone https://github.com/glitch-soc/mastodon.git "$APP_ROOT" && cd "$APP_ROOT"

# install ruby
RUBY_VERSION="$(as_mastodon cat "$APP_ROOT"/.ruby-version)"
as_mastodon RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install --skip-existing "$RUBY_VERSION"
as_mastodon rbenv global "$RUBY_VERSION"

# install npm and gem dependencies
as_mastodon gem install bundler --no-document
as_mastodon bundle config deployment "true"
as_mastodon bundle config without "development test"
as_mastodon bundle install --jobs "$(getconf _NPROCESSORS_ONLN)"
as_mastodon yarn set version classic
as_mastodon yarn install --pure-lockfile --network-timeout 100000

# set up database w/ random alphanumeric password
DB_PASSWORD=$(< /dev/urandom tr -dc A-Za-z0-9 | head -c32; echo)
echo "CREATE USER mastodon WITH PASSWORD '$DB_PASSWORD' CREATEDB" | sudo -u postgres psql -f -

# populate .env.production config
echo "$INSTALLER_WUZ_HERE

LOCAL_DOMAIN=$MASTODON_USERNAME_DOMAIN
WEB_DOMAIN=$MASTODON_DOMAIN

DB_HOST=localhost
DB_USER=mastodon
DB_NAME=mastodon_production
DB_PASS=$DB_PASSWORD

# without pgbouncer:
DB_PORT=5432
# with pgbouncer: https://github.com/jakejarvis/mastodon-utils/wiki/Postgres-&-PgBouncer#pgbouncer
# DB_PORT=6432
# PREPARED_STATEMENTS=false

REDIS_HOST=localhost
REDIS_PORT=6379

SECRET_KEY_BASE=$(as_mastodon RAILS_ENV=production bundle exec rake secret)
OTP_SECRET=$(as_mastodon RAILS_ENV=production bundle exec rake secret)
$(as_mastodon RAILS_ENV=production bundle exec rake mastodon:webpush:generate_vapid_key)

SINGLE_USER_MODE=false
IP_RETENTION_PERIOD=31556952
SESSION_RETENTION_PERIOD=31556952
RAILS_LOG_LEVEL=warn

WEB_CONCURRENCY=3
MAX_THREADS=10
STREAMING_CLUSTER_NUM=1

# using linode, not brand name S3: https://cloud.linode.com/object-storage/buckets/create
# AWS_ACCESS_KEY_ID=XXXXXXXX
# AWS_SECRET_ACCESS_KEY=XXXXXXXX
# S3_ENABLED=true
# S3_BUCKET=$LINODE_BUCKET_NAME
# S3_PROTOCOL=https
# S3_HOSTNAME=us-east-1.linodeobjects.com
# S3_ENDPOINT=https://us-east-1.linodeobjects.com
# S3_ALIAS_HOST=$LINODE_BUCKET_NAME.us-east-1.linodeobjects.com

# get SES credentials: https://us-east-1.console.aws.amazon.com/ses/home?region=us-east-1#/smtp
# SMTP_SERVER=email-smtp.us-east-1.amazonaws.com
# SMTP_PORT=587
# SMTP_FROM_ADDRESS=\"Mastodon <noreply@$MASTODON_DOMAIN>\"
# SMTP_LOGIN=XXXXXXXX
# SMTP_PASSWORD=XXXXXXXX

# https://github.com/jakejarvis/mastodon-utils/wiki/ElasticSearch
# ES_ENABLED=true
# ES_HOST=localhost
# ES_PORT=9200
# ES_USER=optional
# ES_PASS=optional

# https://github.com/jakejarvis/mastodon-utils/wiki/Prometheus-&-Grafana
# STATSD_ADDR=localhost:9125" | as_mastodon tee "$APP_ROOT/.env.production" >/dev/null

# manually setup db
as_mastodon RAILS_ENV=production bundle exec rails db:setup

# apply custom patches & precompile assets
. "$UTILS_ROOT/scripts/apply_patches.sh"

# install latest certbot
# https://certbot.eff.org/instructions?ws=nginx&os=pip
sudo python3 -m venv /opt/certbot/
sudo /opt/certbot/bin/pip install --upgrade pip
sudo /opt/certbot/bin/pip install certbot certbot-nginx
sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot

# ensure nginx hasn't started itself
sudo systemctl stop nginx

# order an ssl certificate from LE
sudo certbot certonly \
  --non-interactive \
  --agree-tos \
  --no-eff-email \
  --domains "$MASTODON_DOMAIN" \
  --email "$MASTODON_ADMIN_EMAIL" \
  --standalone

# configure nginx: sets up symlinks from `/etc/nginx` to confs in this repo
sudo sed -i "$UTILS_ROOT/etc/nginx/sites-available/mastodon.conf" -e "s/fediverse.jarv.is/$MASTODON_DOMAIN/g"
sudo rm -rf /etc/nginx/sites-available
sudo rm -rf /etc/nginx/sites-enabled/*
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo ln -sf "$UTILS_ROOT/etc/nginx/nginx.conf" /etc/nginx/nginx.conf
sudo ln -sf "$UTILS_ROOT/etc/nginx/modules" /usr/lib/nginx/modules
sudo ln -sf "$UTILS_ROOT/etc/nginx/sites-available" /etc/nginx/sites-available
sudo ln -sf /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf
sudo ln -sf /etc/nginx/sites-available/mastodon.conf /etc/nginx/sites-enabled/mastodon.conf
sudo nginx -t
sudo systemctl start nginx

# configure mastodon systemd services
sudo cp "$APP_ROOT"/dist/mastodon-*.service /etc/systemd/system/

# start everything up!
sudo systemctl daemon-reload
sudo systemctl enable --now mastodon-web mastodon-sidekiq mastodon-streaming

# wait a bit to be safe
sleep 5

# create admin account
tootctl accounts create \
  "$MASTODON_ADMIN_USERNAME" \
  --email "$MASTODON_ADMIN_EMAIL" \
  --role Owner \
  --confirmed

# set cleanup tasks to run weekly
# https://docs.joinmastodon.org/admin/setup/#cleanup
(sudo crontab -l; echo -e "\n$INSTALLER_WUZ_HERE
@weekly  bash -c \"$UTILS_ROOT/scripts/weekly_cleanup.sh >> $LOGS_ROOT/cron.log 2>&1\"
") | sudo crontab -

echo "🎉 done! don't forget to fill in .env.production with credentials"
echo "https://$MASTODON_DOMAIN/auth/sign_in"
