#!/usr/bin/env bash
# vim:et:ts=2:sts=2:sw=2

# Get absolute repository root (especially when symlinked)
ROOT="$(realpath "$(dirname "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")")")"

# Load accompanying bash library
source "$ROOT/lib/lib.bash"

BTRFS="${1:-"/var/btrfs"}" # Path to system BTRFS root

if [ -n "$HELP" ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
  say "
  USAGE:
    $(g "${BASH_SOURCE##*/}")  [$(c btrfs-path)]

  DESCRIPTION:
    $(g "${BASH_SOURCE##*/}") configures a TechLit system
    hosted in BTRFS volume at $(c btrfs-path) (default: $(c /var/btrfs))

  NOTE:
    This is run automatically after restoring a system snapshot
  "
  exit 1
fi

# Exit now unless run as root
assert-is-root

#
# Config helpers
#

# Gets an option out of the JSON config
#
# USAGE: get role # => client
# USAGE: get gpu_hacks # => defaults,xf86-video-intel
get() { jq -r ".$1" "$BTRFS/@srv/secure/config.json"; }

# Tests if a string matches a config option exactly
#
# USAGE: is role client # => $? == 1
# USAGE: is role server # => $? == 1
is() { [[ "$(get "$1")" == "$2" ]]; }

# Tests if a string is included in a config option
#
# USAGE: has wifi_hacks defaults # => $? == 0
# USAGE: has wifi_hacks disabled-name # => $? == 1
has() { [[ "$(get "$1")" =~ "$2" ]]; }

#
# Start
#
say "Setting hostname"
get hostname >"$BTRFS/@root/etc/hostname"

say "Setting upstream"
if is role server; then
  echo "bastion" >"$BTRFS/@root/etc/upstream"
else
  echo "server" >"$BTRFS/@root/etc/upstream"
fi

say "Configuring networks"
{
  syscon="$BTRFS/@root/etc/NetworkManager/system-connections"

  run rm "$syscon"/* || true
  run cp "$ROOT/roles/desktop/net/techlit-wifi.nmconnection" "$syscon"
  run sed -i -e "s;^ssid=.*\$;ssid=$(get wifi_name);" "$syscon/techlit-wifi.nmconnection"
  run sed -i -e "s;^psk=.*\$;psk=$(get wifi_password);" "$syscon/techlit-wifi.nmconnection"

  if is role server; then
    run cp "$ROOT/roles/desktop/net/techlit-modem.nmconnection" "$syscon"
    run sed -i -e "s;^pin=.*\$;pin=$(get sim_pin);" "$syscon/techlit-modem.nmconnection"
  fi

  # Surface laptops
  if [ -d /sys/class/net/mlan0 ]; then
    run sed -i -e "s;^interface-name=.*\$;interface-name=mlan0;" "$syscon/techlit-wifi.nmconnection"
  fi

  run chmod 0600 "$syscon/"*
}

if is role server; then
  say "Configuring DHCP"

  mac="$(cat /sys/class/net/eth0/address)"
  sudo sed -i -e "s/hardware ethernet .*;/hardware ethernet $mac;/" \
    "$BTRFS/@root/etc/dhcpd.conf"
  sudo sed -i -e "s/hardware ethernet .*;/hardware ethernet $mac;/" \
    "$BTRFS/@root/etc/dhcpd6.conf"
fi

say "Configuring $(get role) services"
{
  svcs_to_enable=(
    dbus udevd
    desktop preload NetworkManager
    sshd lighttpd nftables
    agetty-tty2
    ctld tl-cmd
  )
  svcs_to_disable=(ngircd dhcpd4)

  if is role server; then
    svcs_to_enable+=(ngircd dhcpd4)
    svcs_to_disable=()
  fi

  say "Enabling services"
  for svc in "${svcs_to_enable[@]}"; do
    if [[ -d "/etc/runit/sv/$svc" ]]; then
      run ln -sf "/etc/runit/sv/$svc" "$BTRFS/@root/etc/runit/runsvdir/default"
    else
      say "$(r WARNING) $(c "/etc/runit/sv/$svc") missing?!"
    fi
  done

  say "Disabling services"
  for svc in "${svcs_to_disable[@]}"; do
    run rm -f "$BTRFS/@root/etc/runit/runsvdir/default/$svc"
  done
}

say "Configuring guest programs"
{
  hostname="$(get hostname)"

  # HexChat
  run sed -i -e "s/^I=.*/I=$hostname/" "$BTRFS/@guest/.config/hexchat/servlist.conf"
  run sed -i -e "s/^irc_user_name = .*/irc_user_name = $hostname/" "$BTRFS/@guest/.config/hexchat/hexchat.conf"
  run sed -i -e "s/^irc_nick1 = .*/irc_nick1 = $hostname/" "$BTRFS/@guest/.config/hexchat/hexchat.conf"
  run sed -i -e "s/^irc_nick2 = .*/irc_nick2 = $hostname-original/" "$BTRFS/@guest/.config/hexchat/hexchat.conf"
  run sed -i -e "s/^irc_nick3 = .*/irc_nick3 = $hostname-impostor/" "$BTRFS/@guest/.config/hexchat/hexchat.conf"

  # STK
  run sed -i -e "s/\"guest\"/\"$hostname\"/" "$BTRFS/@guest/.config/supertuxkart/config-0.10/players.xml"

  # XMoto
  #   WARN: I think this destroys the state ~ Tyler
  # run sed -i -e "s/\"guest\"/\"$hostname\"/" "$BTRFS/@guest/.config/xmoto/config.dat"

  # MineTest
  run sed -i -e "s/^name = .*/name = $hostname/" "$BTRFS/@guest/.minetest/minetest.conf"
}

# We need this to install *-dkms packages
PREFIX="$BTRFS/@root"
say "Mounting Pseudo-filesystems"
tl-chroot-mount
cleanup() {
  tl-chroot-unmount
}

#
# System Hacks
#
say "Considering system hacks..."
for dir in "$ROOT/hacks/system/"*; do
  hack="${dir##*/}"

  if has system_hacks defaults && "$dir/check" || has system_hacks "$hack"; then
    say "Applying $(c $hack) System hack"
    source "$dir/hack"
  else
    say "Skipping $(c $hack) System hack"
  fi
done

#
# WiFi Hacks
#
say "Considering WiFi hacks..."
for dir in "$ROOT/hacks/wifi/"*; do
  hack="${dir##*/}"

  if has wifi_hacks defaults && "$dir/check" || has wifi_hacks "$hack"; then
    say "Applying $(c $hack) WiFi hack"
    source "$dir/hack"
  else
    say "Skipping $(c $hack) WiFi hack"
  fi
done

say "Considering GPU hacks..."
for dir in "$ROOT/hacks/gpu/"*; do
  hack="${dir##*/}"

  if has gpu_hacks defaults && "$dir/check" || has gpu_hacks "$hack"; then
    say "Applying $(c $hack) GPU hack"
    source "$dir/hack"
  else
    say "Skipping $(c $hack) GPU hack"
  fi
done

say "Considering manual hacks..."
if [[ -f "$BTRFS/@srv/secure/hack" ]]; then
  say "Applying manual hack from $(c "$BTRFS/@srv/secure/hack")"
  source "$BTRFS/@srv/secure/hack"
fi

_compare_versions() {
  [[ "$(printf "%s\n%s" "$1" "$2" | sort -V | tail -n 1)" == "$1" ]] && return 0 || return 1
}

# Only restore if override version is newer
say "Restoring component version overrides"
{
  for comp in type help control; do
    if [ -r "$BTRFS/@srv/$comp/.override" ]; then
      override_version=$(cat "$BTRFS/@srv/$comp/.override")
      installed_version=$(cat "$BTRFS/@root/opt/$comp/.version")

      if ! _compare_versions "$installed_version" "$installed_curriculum"; then
        run chpst -u admin "$ROOT"/bin/tl-archive-install "$comp" "$override_version" \
          "$BTRFS/@root/opt/$comp" || :
      fi
    fi
  done
}

# Curriculum
if [ -r "$BTRFS/@srv/curriculum/.override" ]; then
  installed_curriculum=$(cat "$BTRFS/@guest/Desktop/.version")
  override_curriculum=$(cat "$BTRFS/@srv/curriculum/.override")

  if ! _compare_versions "$installed_curriculum" "$override_curriculum"; then
    say "Restoring curriculum v$(c "$override_curriculum")"
    run SKIP_USER_CHECK=1 "$ROOT"/bin/tl-curriculum-install \
      "$BTRFS/@Desktop" "$override_curriculum" || :
  fi
fi

# Unmount system and quiet exit hook
# shellcheck disable=SC2218
cleanup
cleanup() { :; }
say "Done."
