#!/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 as FQDN) " MASTODON_USERNAME_DOMAIN
read -p "Admin username? " MASTODON_ADMIN_USERNAME
read -p "Admin email? " MASTODON_ADMIN_EMAIL

# 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 user named MASTODON_USER (unless it already exists)
if ! id -u "$MASTODON_USER" >/dev/null 2>&1; then
  sudo adduser --gecos "Mastodon" --home "$MASTODON_ROOT" --disabled-login "$MASTODON_USER"
  echo "[ -s \"$UTILS_ROOT/init.sh\" ] && \. \"$UTILS_ROOT/init.sh\" >/dev/null 2>&1" | sudo tee -a "$MASTODON_ROOT/.bashrc" >/dev/null
  sudo chown -R "$MASTODON_USER":"$MASTODON_USER" "$MASTODON_ROOT"
fi

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

# 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] https://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] https://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 DEBIAN_FRONTEND=noninteractive apt-get update
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
  git-core \
  g++ \
  libpq-dev \
  libxml2-dev \
  libxslt1-dev \
  imagemagick \
  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

# install rbenv & ruby-build
# https://github.com/rbenv/rbenv#basic-git-checkout
# https://github.com/rbenv/ruby-build#clone-as-rbenv-plugin-using-git
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"

# install nvm
# https://github.com/nvm-sh/nvm#manual-install
as_mastodon git clone https://github.com/nvm-sh/nvm.git "$NVM_DIR"

# clone vanilla Mastodon & checkout latest version:
as_mastodon git clone https://github.com/mastodon/mastodon.git "$APP_ROOT" && cd "$APP_ROOT"
as_mastodon git config --global --add safe.directory "$APP_ROOT"
as_mastodon git checkout "$(as_mastodon git tag -l | grep -v 'rc[0-9]*$' | sort -V | tail -n 1)"
# uncomment to install glitch-soc fork:
# as_mastodon git remote add glitch-soc https://github.com/glitch-soc/mastodon
# as_mastodon git fetch --all
# as_mastodon git checkout glitch-soc/main

# apply custom patches (skips errors):
for PATCH in "$UTILS_ROOT"/patches/*.patch; do
  as_mastodon git apply --reject --allow-binary-replacement "$PATCH" || true
done
# apply additional glitch-only patches if applicable:
if [ -d "$APP_ROOT/app/javascript/flavours/glitch" ]; then
  for PATCH in "$UTILS_ROOT"/patches/glitch/*.patch; do
    as_mastodon git apply --reject --allow-binary-replacement "$PATCH" || true
  done
fi

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

# install node & yarn
as_mastodon nvm install
as_mastodon nvm use
as_mastodon npm install --global yarn

# 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 install --pure-lockfile

# set up database w/ random alphanumeric password
DB_PASSWORD=$(< /dev/urandom tr -dc A-Za-z0-9 | head -c32; echo)
echo "CREATE USER $MASTODON_USER 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_USER
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

# uses 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=my-bucket
# S3_PROTOCOL=https
# S3_HOSTNAME=us-east-1.linodeobjects.com
# S3_ENDPOINT=https://us-east-1.linodeobjects.com
# S3_ALIAS_HOST=my-bucket.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

# precompile assets
as_mastodon RAILS_ENV=production bundle exec rails assets:precompile

# 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: copies conf files from this repo to /etc/nginx
sudo mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak
sudo cp "$UTILS_ROOT"/etc/nginx/nginx.conf /etc/nginx/nginx.conf
sudo sed -i /etc/nginx/nginx.conf -e "s|user nginx;|user $MASTODON_USER;|g"
sudo mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
sudo cp -f "$UTILS_ROOT"/etc/nginx/sites-available/*.conf /etc/nginx/sites-available/
sudo sed -i /etc/nginx/sites-available/mastodon.conf -e "s|mastodon.example.com|$MASTODON_DOMAIN|g"
sudo sed -i /etc/nginx/sites-available/mastodon.conf -e "s|/home/mastodon/live|$APP_ROOT|g"
sudo ln -sf /etc/nginx/sites-available/mastodon.conf /etc/nginx/sites-enabled/mastodon.conf
# sudo ln -sf /etc/nginx/sites-available/default.conf /etc/nginx/sites-enabled/default.conf
sudo cp -f "$UTILS_ROOT"/etc/nginx/modules/* /usr/lib/nginx/modules/
sudo nginx -t

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

# fix hard-coded paths and usernames in systemd files
# (they already match the defaults from init.sh, so it's likely nothing will change)
sudo sed -i /etc/systemd/system/mastodon-*.service -e "s|/home/mastodon/live|$APP_ROOT|g"
sudo sed -i /etc/systemd/system/mastodon-*.service -e "s|/home/mastodon|$MASTODON_ROOT|g"
sudo sed -i /etc/systemd/system/mastodon-*.service -e "s|User=mastodon|User=$MASTODON_USER|g"

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

# 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 optional credentials"
echo "https://$MASTODON_DOMAIN/auth/sign_in"
