#!/bin/bash
# MCIT Nextcloud Deployment Script
# Version 1.0
# Target: Debian 13 (Trixie), Apache + mod_php + MariaDB
# Installs the latest stable Nextcloud release into /var/www/html.

set -Eeuo pipefail

SCRIPT_VERSION="1.0"
WEBROOT="/var/www/html"
WEBUSER="www-data"
WEBGROUP="www-data"
DB_NAME="nextcloud"
DB_USER="nextcloud"
ADMIN_USER_DEFAULT="ncadmin"
NEXTCLOUD_URL="https://download.nextcloud.com/server/releases/latest.tar.bz2"
NEXTCLOUD_SHA256_URL="https://download.nextcloud.com/server/releases/latest.tar.bz2.sha256"
WORKDIR=""

log() {
    printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$*"
}

fail() {
    printf '\nERROR: %s\n' "$*" >&2
    exit 1
}

cleanup() {
    if [[ -n "${WORKDIR:-}" && -d "$WORKDIR" ]]; then
        rm -rf "$WORKDIR"
    fi
    unset DB_PASSWORD ADMIN_PASSWORD ADMIN_PASSWORD_2 || true
}
trap cleanup EXIT
trap 'printf "\nERROR: Installation failed near line %s.\n" "$LINENO" >&2' ERR

[[ $EUID -eq 0 ]] || fail "Run this script as root."

if [[ -r /etc/os-release ]]; then
    # shellcheck disable=SC1091
    . /etc/os-release
else
    fail "Unable to identify the operating system."
fi

[[ "${ID:-}" == "debian" ]] || fail "This v1.0 script is intended for Debian. Detected: ${PRETTY_NAME:-unknown}."
[[ "${VERSION_ID:-}" == "13" ]] || fail "This v1.0 script is intended for Debian 13. Detected: ${PRETTY_NAME:-unknown}."

printf '\n============================================================\n'
printf ' MCIT Nextcloud Deployment Script v%s\n' "$SCRIPT_VERSION"
printf '============================================================\n'
printf ' OS:            %s\n' "${PRETTY_NAME:-Debian}"
printf ' Web root:      %s\n' "$WEBROOT"
printf ' Database:      %s\n' "$DB_NAME"
printf ' Database user: %s\n' "$DB_USER"
printf ' Admin default: %s\n' "$ADMIN_USER_DEFAULT"
printf ' Nextcloud:     latest stable release\n'
printf '============================================================\n\n'

if [[ -f "$WEBROOT/config/config.php" ]]; then
    fail "An existing Nextcloud config.php was found at $WEBROOT/config/config.php. Refusing to overwrite an existing installation."
fi

read -r -p "Nextcloud administrator username [$ADMIN_USER_DEFAULT]: " ADMIN_USER
ADMIN_USER="${ADMIN_USER:-$ADMIN_USER_DEFAULT}"

while true; do
    read -r -s -p "Password for Nextcloud administrator '$ADMIN_USER': " ADMIN_PASSWORD
    printf '\n'
    [[ -n "$ADMIN_PASSWORD" ]] || { printf 'Password cannot be blank.\n'; continue; }

    read -r -s -p "Confirm administrator password: " ADMIN_PASSWORD_2
    printf '\n'

    if [[ "$ADMIN_PASSWORD" == "$ADMIN_PASSWORD_2" ]]; then
        break
    fi
    printf 'Passwords do not match. Please try again.\n\n'
done
unset ADMIN_PASSWORD_2

printf '\nThis will install a new Nextcloud instance into %s.\n' "$WEBROOT"
read -r -p "Continue? [Y/n]: " CONFIRM
case "${CONFIRM:-Y}" in
    y|Y|yes|YES|Yes) ;;
    *) printf 'Installation cancelled.\n'; exit 0 ;;
esac

# Hex avoids SQL/shell quoting problems while providing 256 bits of entropy.
DB_PASSWORD="$(openssl rand -hex 32 2>/dev/null || true)"
if [[ -z "$DB_PASSWORD" ]]; then
    # openssl may not exist before package installation on an unusually minimal image.
    DB_PASSWORD="$(head -c 32 /dev/urandom | od -An -tx1 | tr -d ' \n')"
fi
[[ ${#DB_PASSWORD} -ge 48 ]] || fail "Failed to generate a secure database password."

log "Updating package indexes"
apt-get update

log "Installing Apache, MariaDB, PHP and Nextcloud prerequisites"
DEBIAN_FRONTEND=noninteractive apt-get install -y \
    apache2 \
    mariadb-server \
    libapache2-mod-php \
    php \
    php-cli \
    php-common \
    php-gd \
    php-mysql \
    php-curl \
    php-mbstring \
    php-intl \
    php-gmp \
    php-xml \
    php-imagick \
    php-zip \
    php-bcmath \
    php-bz2 \
    php-ldap \
    php-apcu \
    php-smbclient \
    smbclient \
    bzip2 \
    ca-certificates \
    curl \
    wget \
    openssl \
    cron

systemctl enable --now mariadb apache2 cron >/dev/null

log "Checking PHP runtime and required modules"
PHP_VERSION="$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')"
printf 'PHP version: %s\n' "$(php -v | head -1)"

required_modules=(curl gd intl mbstring mysqli pdo_mysql SimpleXML xmlreader xmlwriter zip apcu gmp)
missing_modules=()
for module in "${required_modules[@]}"; do
    if ! php -m | grep -qi "^${module}$"; then
        missing_modules+=("$module")
    fi
done
if (( ${#missing_modules[@]} > 0 )); then
    fail "Required PHP module(s) not active: ${missing_modules[*]}"
fi

if php -m | grep -qi '^smbclient$'; then
    printf 'PHP smbclient module: enabled\n'
else
    printf 'WARNING: PHP smbclient module was installed but is not currently visible in php -m.\n'
fi

log "Downloading the latest stable Nextcloud release"
WORKDIR="$(mktemp -d /tmp/mcit-nextcloud.XXXXXX)"
cd "$WORKDIR"
wget -q --show-progress -O latest.tar.bz2 "$NEXTCLOUD_URL"
wget -q -O latest.tar.bz2.sha256 "$NEXTCLOUD_SHA256_URL"

log "Verifying Nextcloud SHA-256 checksum"
EXPECTED_SHA256="$(awk '{print $1; exit}' latest.tar.bz2.sha256)"
ACTUAL_SHA256="$(sha256sum latest.tar.bz2 | awk '{print $1}')"
[[ "$EXPECTED_SHA256" =~ ^[0-9a-fA-F]{64}$ ]] || fail "Downloaded checksum file did not contain a valid SHA-256 value."
[[ "${ACTUAL_SHA256,,}" == "${EXPECTED_SHA256,,}" ]] || fail "Nextcloud archive SHA-256 verification failed."
printf 'SHA-256 verified: %s\n' "$ACTUAL_SHA256"

log "Extracting Nextcloud"
tar -xjf latest.tar.bz2
[[ -f "$WORKDIR/nextcloud/occ" ]] || fail "Nextcloud archive did not extract as expected."

if [[ -d "$WEBROOT" ]]; then
    BACKUP_WEBROOT="/var/www/html.orig"
    if [[ -e "$BACKUP_WEBROOT" ]]; then
        BACKUP_WEBROOT="/var/www/html.orig.$(date '+%Y%m%d-%H%M%S')"
    fi
    log "Moving existing Apache document root to $BACKUP_WEBROOT"
    mv "$WEBROOT" "$BACKUP_WEBROOT"
fi

log "Installing Nextcloud into $WEBROOT"
mv "$WORKDIR/nextcloud" "$WEBROOT"

# Nextcloud's CLI installer must run as the HTTP user. Temporarily give it
# ownership of the tree; the user's established root:www-data model is
# restored after installation.
chown -R "$WEBUSER:$WEBGROUP" "$WEBROOT"

log "Creating MariaDB database and generated database account"
mariadb --protocol=socket <<SQL
CREATE DATABASE \`${DB_NAME}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
CREATE USER '${DB_USER}'@'localhost' IDENTIFIED BY '${DB_PASSWORD}';
GRANT ALL PRIVILEGES ON \`${DB_NAME}\`.* TO '${DB_USER}'@'localhost';
FLUSH PRIVILEGES;
SQL

log "Configuring Apache for Nextcloud"
cat > /etc/apache2/sites-available/nextcloud.conf <<'APACHEEOF'
<Directory /var/www/html/>
    Options +FollowSymlinks
    AllowOverride All
    Require all granted

    <IfModule mod_dav.c>
        Dav off
    </IfModule>

    SetEnv HOME /var/www/html
    SetEnv HTTP_HOME /var/www/html
</Directory>
APACHEEOF

a2ensite nextcloud >/dev/null
a2enmod rewrite >/dev/null
if a2query -m dav 2>/dev/null | grep -q 'enabled'; then
    a2dismod dav >/dev/null || true
fi

apache2ctl configtest
systemctl reload apache2

log "Installing Nextcloud and creating administrator '$ADMIN_USER'"
cd "$WEBROOT"
runuser -u "$WEBUSER" -- php occ maintenance:install \
    --database mysql \
    --database-name "$DB_NAME" \
    --database-host localhost \
    --database-user "$DB_USER" \
    --database-pass "$DB_PASSWORD" \
    --admin-user "$ADMIN_USER" \
    --admin-pass "$ADMIN_PASSWORD"

unset ADMIN_PASSWORD

log "Adding this server's primary IPv4 address as a trusted domain"
PRIMARY_IP="$(ip -4 route get 1.1.1.1 2>/dev/null | awk '{for (i=1;i<=NF;i++) if ($i=="src") {print $(i+1); exit}}')"
if [[ -n "$PRIMARY_IP" ]]; then
    runuser -u "$WEBUSER" -- php occ config:system:set trusted_domains 1 --value="$PRIMARY_IP" >/dev/null
    printf 'Trusted IP added: %s\n' "$PRIMARY_IP"
else
    printf 'WARNING: Could not determine a primary IPv4 address. Add your hostname/IP to trusted_domains manually.\n'
fi

log "Configuring cron background jobs"
runuser -u "$WEBUSER" -- php occ background:cron >/dev/null
CRON_LINE='*/5  *  *  *  * /usr/bin/php -f /var/www/html/cron.php'
CURRENT_CRON="$(crontab -u "$WEBUSER" -l 2>/dev/null || true)"
if ! grep -Fqx "$CRON_LINE" <<< "$CURRENT_CRON"; then
    {
        printf '%s\n' "$CURRENT_CRON"
        printf '%s\n' "$CRON_LINE"
    } | sed '/^[[:space:]]*$/d' | crontab -u "$WEBUSER" -
fi

log "Applying MCIT Nextcloud ownership and permissions"
mkdir -p "$WEBROOT/data" "$WEBROOT/assets" "$WEBROOT/updater"

find "$WEBROOT" -type f -print0 | xargs -0 chmod 0640
find "$WEBROOT" -type d -print0 | xargs -0 chmod 0750
chmod 0755 "$WEBROOT"

chown -R root:"$WEBGROUP" "$WEBROOT"
for writable_dir in apps custom_apps assets config data themes updater; do
    if [[ -d "$WEBROOT/$writable_dir" ]]; then
        chown -R "$WEBUSER:$WEBGROUP" "$WEBROOT/$writable_dir"
    fi
done

chmod +x "$WEBROOT/occ"
if [[ -f "$WEBROOT/.htaccess" ]]; then
    chmod 0644 "$WEBROOT/.htaccess"
    chown root:"$WEBGROUP" "$WEBROOT/.htaccess"
fi
if [[ -f "$WEBROOT/data/.htaccess" ]]; then
    chmod 0644 "$WEBROOT/data/.htaccess"
    chown root:"$WEBGROUP" "$WEBROOT/data/.htaccess"
fi

log "Running final health checks"
apache2ctl configtest
systemctl is-active --quiet apache2 || fail "Apache is not running."
systemctl is-active --quiet mariadb || fail "MariaDB is not running."

NC_STATUS="$(runuser -u "$WEBUSER" -- php "$WEBROOT/occ" status)"
printf '%s\n' "$NC_STATUS"

NC_VERSION="$(runuser -u "$WEBUSER" -- php "$WEBROOT/occ" status --output=json 2>/dev/null | php -r '$j=json_decode(stream_get_contents(STDIN),true); echo $j["versionstring"] ?? $j["version"] ?? "unknown";' 2>/dev/null || true)"
[[ -n "$NC_VERSION" ]] || NC_VERSION="installed"

printf '\n============================================================\n'
printf ' NEXTCLOUD INSTALLATION COMPLETE\n'
printf '============================================================\n'
printf ' Nextcloud:     %s\n' "$NC_VERSION"
printf ' Web root:      %s\n' "$WEBROOT"
printf ' Database:      %s\n' "$DB_NAME"
printf ' Database user: %s\n' "$DB_USER"
printf ' Admin user:    %s\n' "$ADMIN_USER"
printf ' PHP:           %s\n' "$PHP_VERSION"
printf ' Background:    cron (every 5 minutes)\n'
printf ' Apache:        active\n'
printf ' MariaDB:       active\n'
if [[ -n "$PRIMARY_IP" ]]; then
    printf ' Browse to:     http://%s/\n' "$PRIMARY_IP"
fi
printf '\nThe generated database password is stored by Nextcloud in:\n'
printf ' %s/config/config.php\n' "$WEBROOT"
printf '\nNext suggested step: configure the customer hostname/DNS and HTTPS.\n'
printf '============================================================\n'
