#!/bin/bash
set -euo pipefail

# Install MySQL
# Install Apache
# Install PHP8 and extensions


# TODO Only attempt to change Apache PHP.ini if AllowOverride is None
# Otherwise print warning.


# Determine whether we have yum or apt (and bail if neither)
HAS_APT=false
HAS_YUM=false
if [ -x "$(command -v apt)" ]; then
  HAS_APT=true
fi
if [ -x "$(command -v yum)" ]; then
  HAS_YUM=true
fi
if [ $HAS_APT = false ] && [ $HAS_YUM = false ]; then
  echo "Neither apt nor yum was found"
  echo "Aborting"
  exit 1
fi

# Make sure we have PHP
if ! [ -x "$(command -v php)" ]; then
  echo "PHP not found"
  echo "Aborting"
  exit 1
fi

# Make sure it's a high enough version
PHPVERSION="$(php -v | head -n 1 | cut -d " " -f 2 | cut -f1-2 -d"." )"
PHP_OK="$(php -r 'echo version_compare(phpversion(),"8.0.0",">")?"1":"0";')"
if [ $PHP_OK = 0 ]; then
  echo "PHP version must be at least 8.0, currently $PHPVERSION"
  exit 1
fi


#Install some PHP packages, and CIFS utils
if [ $HAS_APT = true ]; then
  echo "Running apt-get update - some PHP modules are not found unless we do this first"
  apt-get update
  echo "Configuring PHP - installing Sybase module to communicate with Formulatrix SQL Server database"
  apt-get --assume-yes install php"$PHPVERSION"-sybase
  echo "Configuring PHP - installing MySQL module to communicate with MySQL database"
  apt-get --assume-yes install php"$PHPVERSION"-mysql
  echo "Configuring PHP - installing GD module for image manipulation"
  apt-get --assume-yes install php$PHPVERSION-gd
  echo "Configuring PHP - installing cURL module for remote communication"
  apt-get --assume-yes install php$PHPVERSION-curl
  echo "Installing cifs-utils package to enable mounting Formulatrix/Windows image stores"
  apt-get --assume-yes install cifs-utils
else #We know we have yum, because we checked earlier
  rm ./temp.php
  cat <<EOT >> ./temp.php
  <?php
  echo "\n";
  \$extensions=[
    'gd','curl','pdo_dblib','freetds'
  ];
  \$notInstalled=[];
  foreach(\$extensions as \$ext){
    if(extension_loaded(\$ext)){
      echo "\$ext is installed\n";
    } else {
      \$notInstalled[]=\$ext;
    }
  }
  if(empty(\$notInstalled)){ exit(0); }
  foreach(\$notInstalled as \$ext){
    echo "PHP extension \$ext is not installed. Please install it.\n";
  }
  exit(1);
EOT
  php ./temp.php
  rm ./temp.php
fi

# Make sure we have MySQL
if ! [ -x "$(command -v mysql)" ]; then
  echo "MySQL not found"
  echo "Aborting"
  exit 1
fi


# Determine directories, php.ini, and apache username and config file
PHPINIFILE="$(php -r 'echo php_ini_loaded_file();')"
APACHEUSER="$(ps -ef | egrep '(httpd|apache2|apache)' | grep -v `whoami` | grep -v root | head -n1 | awk '{print $1}')"
APACHECONF=$(apachectl -V 2>/dev/null | awk -F'"' '/HTTPD_ROOT/{r=$2}/SERVER_CONFIG_FILE/{c=$2}END{print c~/^\//?c:r"/"c}')
INSTALLDIR="$(dirname -- "$(realpath $0)")"
WWWROOT="$(dirname -- "${INSTALLDIR}")"

#Set defaults, otherwise "unbound variable" if not specified
DBHOST=""
DBNAME=""
DBUSER=""
ICEBEARSTORE=""
LOGDIR=""

# Parse arguments
while [[ $# -gt 0 ]]; do
  case $1 in
    --dbhost)
      DBHOST=$2
      shift #past argument
      shift #past value
    ;;
    --dbname)
      DBNAME=$2
      shift #past argument
      shift #past value
    ;;
    --dbuser)
      DBUSER=$2
      shift #past argument
      shift #past value
    ;;
    --store)
      ICEBEARSTORE=$2
      shift #past argument
      shift #past value
    ;;
    --logs)
      LOGDIR=$2
      shift #past argument
      shift #past value
    ;;
    --defaults)
      shift #past argument
      DBHOST="localhost"
      DBNAME="icebear"
      DBUSER="icebear"
      ICEBEARSTORE="/icebearstore/"
      LOGDIR="/var/log/icebear/"
    ;;
    --icebox)
      #TODO Bail if not all lowercase letters
      ICEBOX=$2
      if [[ ! $ICEBOX ]]; then
        echo "IceBox name not specified"
        echo "Use --icebox abc, where abc is the subdomain, e.g., abc.icebox.icebear.fi"
        exit 1
      elif ! [[ $ICEBOX =~ ^[a-z]+$ ]]; then
        echo "IceBox name must be all lowercase letters"
        exit 1
      fi
      shift #past argument
      shift #past value
      DBHOST=localhost
      DBNAME=icebear_${ICEBOX}
      DBUSER=icebear_${ICEBOX}
      ICEBEARSTORE=/icebearstore-${ICEBOX}/
      LOGDIR=/var/log/icebear-${ICEBOX}/
    ;;
    -*)
      echo "Unknown argument $1"
      exit 1
    ;;
  esac
done


# Verify all values set
BAIL=0
if [[ ! $DBHOST ]]; then
  BAIL=1
  echo "Database host --dbhost not specified"
fi
if [[ ! $DBNAME ]]; then
  BAIL=1
  echo "Database name --dbname not specified"
fi
if [[ ! $DBUSER ]]; then
  BAIL=1
  echo "Database user --dbuser not specified"
fi
if [[ ! $ICEBEARSTORE ]]; then
  BAIL=1
  echo "Store directory --store not specified"
fi
if [[ ! $LOGDIR ]]; then
  BAIL=1
  echo "Log directory --logs not specified"
fi
if [[ ! $APACHEUSER ]]; then
  BAIL=1
  echo "Could not determine Apache user"
fi
if [[ ! $PHPINIFILE ]]; then
  BAIL=1
  echo "Could not determine PHP ini file"
fi
if [[ $BAIL -eq 1 ]]; then
  echo "Aborting"
  echo "Run with --defaults to install with host and user icebear, store /icebearstore/, and logs at /var/log/icebear/"
  exit 1
fi

# Strip trailing slashes
ICEBEARSTORE="${ICEBEARSTORE%/}"
INSTALLDIR="${INSTALLDIR%/}"
WWWROOT="${WWWROOT%/}"
LOGDIR="${LOGDIR%/}"

# Make storage and log directories
if [[ -d $ICEBEARSTORE ]]; then
  echo "Storage directory $ICEBEARSTORE already exists"
  if [ -z "$( ls -A "$ICEBEARSTORE" )" ]; then
    echo "Directory is empty, proceeding"
  else
    echo "Directory is not empty, aborting"
    exit 1
  fi
else
  echo "Making storage directory $ICEBEARSTORE"
  mkdir "$ICEBEARSTORE"
  chown "$APACHEUSER" "$ICEBEARSTORE"
fi
if [[ -d $LOGDIR ]]; then
  echo "Logs directory $LOGDIR already exists"
  if [ -z "$( ls -A $LOGDIR )" ]; then
    echo "Directory is empty, proceeding"
  else
    echo "Directory is not empty, aborting"
    exit 1
  fi
else
  echo "Making log directory $LOGDIR"
  mkdir "$LOGDIR"
  chown "$APACHEUSER" "$LOGDIR"
fi

#Create a random database password
DBPASS="$( openssl rand -hex 10 )"

# Write the config file with database connection details
CONFIGFILE=$WWWROOT/conf/config.ini
mv "$CONFIGFILE" "$CONFIGFILE".old
echo "Writing IceBear config file"
cat <<EOT >> "$CONFIGFILE"
;security:
;<?php exit(); __halt_compiler();
dbType=mysql
dbHost=$DBHOST
dbUser=$DBUSER
dbPass=$DBPASS
dbName=$DBNAME
EOT

# Create the database and user, then create the tables
mysql -e "CREATE DATABASE $DBNAME DEFAULT CHARACTER SET utf8 COLLATE utf8_bin;"
mysql -e "CREATE USER '$DBUSER'@'$DBHOST' IDENTIFIED BY '$DBPASS';"
mysql -e "GRANT INSERT,DELETE,SELECT,UPDATE,CREATE,DROP,INDEX,ALTER,CREATE TEMPORARY TABLES,CREATE VIEW,TRIGGER,SHOW VIEW,EVENT,CREATE ROUTINE,ALTER ROUTINE,EXECUTE,REFERENCES ON $DBNAME.* TO '$DBUSER'@'$DBHOST';"
mysql -e "FLUSH PRIVILEGES;"
echo "Creating IceBear database tables"
mysql --database "$DBNAME" < "$INSTALLDIR"/icebeardatabase.sql


echo "Setting up temporary cron job for later install tasks"
croncmd="$INSTALLDIR/rootinstalltasks.sh"
cronjob="* * * * * $croncmd"
( crontab -l | grep -v -F "$croncmd" || : ; echo "$cronjob" ) | crontab -

if [ -f $WWWROOT/index.html ]; then
  echo "Renaming default Apache index file"
  mv "$WWWROOT"/index.html "$WWWROOT"/index_old.html
fi
if [ -x "$(command -v a2enmod)" ]; then
  # If no a2enmod, probably CentOS, where mod_rewrite is enabled already
  echo "Configuring Apache - enable mod_rewrite"
  a2enmod -q rewrite
fi

#
# BEGIN set minimum upload_max_filesize post_max_filesize
# Bash code generated by ChatGPT
#

# Minimum desired values
MIN_SIZE="8M"

# Function to update ini settings if smaller than MIN_SIZE
update_ini() {
    local ini_file="$1"
    echo "Processing $ini_file ..."

    # Backup original
    cp "$ini_file" "${ini_file}.bak_$(date +%Y%m%d%H%M%S)"

    for key in upload_max_filesize post_max_filesize; do
        current=$(grep -E "^$key\s*=" "$ini_file" | tail -n1 | awk -F= '{gsub(/ /,"",$2); print $2}')
        if [[ -z "$current" ]]; then
            echo "$key not found, adding it"
            echo "$key = $MIN_SIZE" >> "$ini_file"
            continue
        fi

        # Convert values to bytes for comparison
        convert_bytes() {
            local val="$1"
            local num=${val%[KMGkmg]}
            local unit=${val##$num}
            case "${unit^^}" in
                K) echo $((num*1024)) ;;
                M) echo $((num*1024*1024)) ;;
                G) echo $((num*1024*1024*1024)) ;;
                *) echo "$num" ;;
            esac
        }

        current_bytes=$(convert_bytes "$current")
        min_bytes=$(convert_bytes "$MIN_SIZE")

        if (( current_bytes < min_bytes )); then
            echo "Updating $key from $current to $MIN_SIZE"
            # Use sed to replace the value
            sed -i -E "s/^($key\s*=).*/\1 $MIN_SIZE/" "$ini_file"
        else
            echo "$key is already $current, OK"
        fi
    done
}

# ---------------------------
# 1. Detect CLI php.ini
# ---------------------------
CLI_PHPINI=$(php --ini | grep "Loaded Configuration File" | awk '{print $NF}')
update_ini "$CLI_PHPINI"

# ---------------------------
# 2. Detect Apache php.ini
# ---------------------------

TMPFILE="/var/www/html/phpinfo_tmp.php"
echo "<?php phpinfo(INFO_GENERAL);" > "$TMPFILE"
chmod 644 "$TMPFILE"

# Fetch via Apache
APACHE_PHPINI=$(curl -s http://localhost/phpinfo_tmp.php \
    | grep 'Loaded Configuration File' \
    | sed -n 's/.*<td class="v">\([^<]*\)<\/td>.*/\1/p' \
    | tr -d ' ')

# Remove temp file
rm "$TMPFILE"

# If empty, warn
if [[ -z "$APACHE_PHPINI" ]]; then
    echo "Warning: Could not detect Apache php.ini"
else
    update_ini "$APACHE_PHPINI"
fi

#
# END set minimum upload_max_filesize post_max_filesize
# Bash code generated by ChatGPT
#

echo "Configuring PHP - modifying CLI php.ini file to enable MSSQL secure connection in Formulatrix importer"
cat <<EOT >> "$CLI_PHPINI"
#Added by IceBear installer, allows connection to MSSQL without pre-existing DSN
mssql.secure_connection = on
EOT

# MUST appear after determining Apache php.ini file, in case these changes take and we redirect away from the temp file
echo "Configuring Apache - set AllowOverride"
cp -a "$APACHECONF" "$APACHECONF.bak.$(date +%s)"
awk -v d1="${WWWROOT%/}" -v d2="$(dirname -- "${WWWROOT%/}")" '
  BEGIN {
    gsub(/[][(){}.^$+*?|\\]/, "\\\\&", d1)
    gsub(/[][(){}.^$+*?|\\]/, "\\\\&", d2)
  }

  # Prefer exact match
  $0 ~ "^[[:space:]]*<Directory[[:space:]]+(\"" d1 "/?\"|" d1 "/?)[[:space:]]*>[[:space:]]*$" {
    inblock=1; matched=1
  }

  # Fallback to parent only if no exact match seen yet
  !matched && $0 ~ "^[[:space:]]*<Directory[[:space:]]+(\"" d2 "/?\"|" d2 "/?)[[:space:]]*>[[:space:]]*$" {
    inblock=1
  }

  inblock && /^[[:space:]]*<\/Directory>/ { inblock=0 }

  inblock && /^[[:space:]]*AllowOverride[[:space:]]+None([[:space:]]|$)/ {
    sub(/None/, "All")
  }

  { print }
' "$APACHECONF" > "$APACHECONF.new"
mv "$APACHECONF.new" "$APACHECONF"

apachectl -t || {
  echo "Apache config test failed — restoring backup" >&2
  mv "$APACHECONF.bak."* "$APACHECONF"
  exit 1
}

#Restart Apache
echo "Restarting Apache to refresh Apache and PHP config"
systemctl restart apache2

#Set up a firewall
if [ -x "$(command -v ufw)" ]; then
  echo "Setting up a firewall (ufw)"
  ufw default deny incoming
  ufw default allow outgoing
  ufw allow http
  ufw allow https
  ufw allow ssh
  systemctl enable ufw.service
elif [ -x "$(command -v firewall-cmd)" ]; then
  echo "Setting up a firewall (firewalld)"
  yum install -y firewalld
  systemctl start firewalld
  firewall-cmd --add-service=ssh
  firewall-cmd --add-service=http
  firewall-cmd --add-service=https
  firewall-cmd --permanent --add-service=ssh
  firewall-cmd --permanent --add-service=http
  firewall-cmd --permanent --add-service=https
  firewall-cmd --set-default-zone=public
  systemctl enable firewalld
  firewall-cmd --reload
fi

touch $INSTALLDIR/preInstallDone
chown -R $APACHEUSER $WWWROOT

echo " **********************************************************************************"
echo " *                                                                                *"
echo " * IceBear pre-install script complete.                                           *"
echo " *                                                                                *"
echo " * FIREWALL                                                                       *"
echo " *                                                                                *"
if [ -x "$(command -v ufw)" ]; then
  echo " * This install script has activated a firewall (ufw) and created some basic      *"
  echo " * rules, but YOU are responsible for ensuring the security of this machine! Ask  *"
  echo " * your IT department for advice.                                                 *"
elif [ -x "$(command -v firewall-cmd)" ]; then
  echo " * This install script has activated a firewall (firewalld) and created some      *"
  echo " * basic rules, but YOU are responsible for the security of this machine! Ask     *"
  echo " * your IT department for advice.                                                 *"
else
  echo " * You MUST configure a firewall. Ask your IT department for advice.              *"
fi
echo " *                                                                                *"
echo " * SECURE HTTP (HTTPS)                                                            *"
echo " *                                                                                *"
echo " * Any web server, including this one, should be configured to encrypt traffic    *"
echo " * via secure HTTP (URLs begin with https:// instead of http://). This is NOT     *"
echo " * the default, meaning that usernames, passwords, and scientific data travel     *"
echo " * UNENCRYPTED between server and browser. You really should configure Apache to  *"
echo " * use secure HTTP. You will almost certainly need to get a certificate from your *"
echo " * IT department for this. Ask them for advice.                                   *"
echo " *                                                                                *"
echo " * IMPORTANT: STORAGE AND BACKUP DIRECTORIES                                      *"
echo " *                                                                                *"
echo " * By default, IceBear stores file uploads and imported images at /icebearstore   *"
echo " * and NO BACKUP is configured. If you choose to put the IceBear store in a       *"
echo " * different location, you must create that directory NOW and ensure that it is   *"
echo " * WRITABLE by the Apache user (probably www-data).                               *"
echo " *                                                                                *"
echo " * Unless you have another backup mechanism in place, you really should have      *"
echo " * IceBear take backups. The backups should AT LEAST be on a different disk, but  *"
echo " * should really be as far from this machine as is practical. As with the storage *"
echo " * directory, you need to mount the backup directory now. The backup directory    *"
echo " * must be WRITABLE by the Apache user (probably www-data).                       *"
echo " *                                                                                *"
echo " * However you back up IceBear, you should check regularly that backups are being *"
echo " * taken AND that you can restore from them!                                      *"
echo " *                                                                                *"
echo " * You will configure the storage and backup directories later in the install     *"
echo " * process, but the directories MUST EXIST before you continue.                   *"
echo " *                                                                                *"
echo " * DATABASE CREDENTIALS                                                           *"
echo " *                                                                                *"
echo " * No root password is required. The root user can log into the database without  *"
echo " * further authentication. This is the default behaviour in Ubuntu.               *"
echo " *                                                                                *"
echo " * The IceBear database credentials, used by the application, can be found in     *"
echo " * $WWWROOT/conf/config.ini                                                  *"
echo " *                                                                                *"
echo " * Continue in your web browser by going to the index page on this server,        *"
echo " * e.g., http://this-machine.myuni.edu                                            *"
echo " *                                                                                *"
echo " **********************************************************************************"

####################
# End of pre-install
####################

#For reference only
#To add it to the crontab, with no duplication:
#( crontab -l | grep -v -F "$croncmd" ; echo "$cronjob" ) | crontab -
#To remove it from the crontab:
#( crontab -l | grep -v -F "$croncmd" ) | crontab -
