#!/bin/bash
################################################################################
# HiTechCloud Panel - native installer (no containers in the backend)
#
# Usage:
#   curl -sSL https://raw.githubusercontent.com/hitechcloud-vietnam/HiTechCloud-Panel/main/INSTALL.sh | bash
#
# Everything the panel needs runs as a host service under systemd: the panel
# itself, the 80/443 front-end, the WebEngines, PHP-FPM, MariaDB, Redis, DNS,
# mail and FTP. Podman is installed only so that users can run applications
# from the App Store - no part of the control panel depends on it.
#
# The previous container-based installer is kept at legacy/INSTALL-docker.sh.
################################################################################

set -euo pipefail

REPO="hitechcloud-vietnam/HiTechCloud-Panel"
BRANCH="${BRANCH:-main}"
INSTALL_DIR="/opt/hitechcloud"
RUNTIME_DIR="/usr/local/hitechcloud"
PANEL_PORT="${PANEL_PORT:-2083}"
ADMIN_PORT="${ADMIN_PORT:-2087}"
DEFAULT_PHP="${DEFAULT_PHP:-8.3}"
ENGINES="${ENGINES:---all-engines}"
WITH_COMPONENTS="${WITH_COMPONENTS:-db,redis,dns,ftp}"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; BLUE='\033[0;34m'; NC='\033[0m'
log()  { echo -e "${GREEN}[✓]${NC} $*"; }
step() { echo -e "\n${BLUE}==>${NC} ${*}"; }
warn() { echo -e "${YELLOW}[!]${NC} $*"; }
err()  { echo -e "${RED}[✗]${NC} $*" >&2; exit 1; }

banner() {
    echo -e "${BLUE}"
    cat <<'BANNER'
╔══════════════════════════════════════════════════════════╗
║   HiTechCloud Panel - native installation (2.1.0)        ║
║   Multi-WebServer Hosting · no containers in the backend ║
║   https://hitechcloud.org                                ║
╚══════════════════════════════════════════════════════════╝
BANNER
    echo -e "${NC}"
}

[ "$EUID" -ne 0 ] && err "Run as root: sudo bash INSTALL.sh"
banner

# ---- 0. Supported OS -------------------------------------------------------
. /etc/os-release 2>/dev/null || err "Cannot read /etc/os-release."
case "${ID:-}${ID_LIKE:-}" in
    *debian*|*ubuntu*) OS_FAMILY=debian ;;
    *rhel*|*fedora*|*centos*) OS_FAMILY=rhel ;;
    *) err "Unsupported OS '${PRETTY_NAME:-unknown}'. Debian, Ubuntu, AlmaLinux and Rocky are supported." ;;
esac
log "Detected ${PRETTY_NAME:-$ID} (${OS_FAMILY})"

# The ports the native architecture claims. Finding one busy now is far
# cheaper than finding out after MariaDB has been installed.
step "Checking required ports"
BUSY=""
for port in 80 443 8188 8189 8190 8288 8289 8290 "$PANEL_PORT" "$ADMIN_PORT"; do
    if ss -Hltn "sport = :${port}" 2>/dev/null | grep -q .; then
        holder=$(ss -Hltnp "sport = :${port}" 2>/dev/null | grep -oE 'users:\(\("[^"]+"' | head -n1 | tr -d '"' | sed 's/users:((//')
        case "$holder" in
            nginx|httpd|apache2|litespeed|caddy) log "port ${port} held by ${holder} (will be taken over)" ;;
            *) warn "port ${port} is in use by '${holder:-unknown}'"; BUSY="${BUSY} ${port}" ;;
        esac
    fi
done
[ -n "$BUSY" ] && err "Free these ports first:${BUSY}"
log "All required ports available"

# ---- 1. Base packages ------------------------------------------------------
step "Installing base packages"
if [ "$OS_FAMILY" = debian ]; then
    export DEBIAN_FRONTEND=noninteractive
    apt-get update -qq
    apt-get install -y -qq git curl wget jq openssl cron rsync ca-certificates \
        gnupg lsb-release iproute2 net-tools quota acl unzip zip tar logrotate >/dev/null
else
    (command -v dnf >/dev/null && dnf install -y -q git curl wget jq openssl cronie rsync \
        ca-certificates gnupg2 iproute net-tools quota acl unzip zip tar logrotate) >/dev/null \
        || yum install -y -q git curl wget jq openssl cronie rsync ca-certificates gnupg2 >/dev/null
fi
log "Base packages installed"

# ---- 2. Repository ---------------------------------------------------------
# Once the repositories are private, every fetch below needs a credential.
# HITECHCLOUD_GITHUB_TOKEN is read from the environment when set - a token with
# read access to the organisation's repositories - and configured for
# github.com as a whole so the submodules and the release download authenticate
# too. It is deliberately optional: a public install needs nothing.
if [ -n "${HITECHCLOUD_GITHUB_TOKEN:-}" ]; then
    git config --global url."https://x-access-token:${HITECHCLOUD_GITHUB_TOKEN}@github.com/".insteadOf "https://github.com/"
fi

step "Fetching HiTechCloud Panel"
if [ -d "$INSTALL_DIR/.git" ]; then
    git -C "$INSTALL_DIR" fetch --quiet origin
    git -C "$INSTALL_DIR" reset --quiet --hard "origin/$BRANCH"
    log "Repository updated"
else
    git clone --quiet --branch "$BRANCH" "https://github.com/$REPO.git" "$INSTALL_DIR"
    log "Repository cloned to ${INSTALL_DIR}"
fi
# The panel database schema lives in the `configuration` submodule, so a clone
# without it leaves the panel with an empty database and no obvious reason why.
git -C "$INSTALL_DIR" submodule update --init --recursive --depth 1 configuration >/dev/null 2>&1 \
    || warn "Could not fetch the configuration submodule - the schema step below will say so."
VERSION=$(cat "$INSTALL_DIR/hitechcloudpanel/version" 2>/dev/null || echo "2.1.0")

# ---- 3. Credentials --------------------------------------------------------
# These live under /etc, not in the checkout. $INSTALL_DIR is a git working
# tree of a public repository, and a generated secret sitting in it is one
# `git add -A` away from being published.
CRED_DIR="/etc/hitechcloud/hitechcloud/conf"
CRED_FILE="${CRED_DIR}/credentials.env"
mkdir -p "$CRED_DIR"
chmod 750 "$CRED_DIR"

# Move a file written by an earlier build out of the checkout.
if [ -f "$INSTALL_DIR/.env" ] && [ ! -f "$CRED_FILE" ]; then
    mv "$INSTALL_DIR/.env" "$CRED_FILE"
    chmod 600 "$CRED_FILE"
    warn "Moved credentials out of the repository: ${INSTALL_DIR}/.env -> ${CRED_FILE}"
fi
rm -f "$INSTALL_DIR/.env"

if [ ! -f "$CRED_FILE" ]; then
    DB_PASS=$(openssl rand -base64 24 | tr -d '/+=')
    SERVER_IP=$(curl -4s --max-time 5 ifconfig.me 2>/dev/null || curl -4s --max-time 5 api.ipify.org 2>/dev/null || hostname -I | awk '{print $1}')
    # Every value is quoted: this file is sourced, and an unquoted value with a
    # space in it (BRAND_NAME) runs its second word as a command.
    # No admin password is generated or stored: the administrator authenticates
    # with this server's own root password, which the operator already has.
    cat > "$CRED_FILE" <<EOF
VERSION="${VERSION}"
ARCHITECTURE="native"
SERVER_IP="${SERVER_IP}"
PANEL_PORT="${PANEL_PORT}"
ADMIN_PORT="${ADMIN_PORT}"
MYSQL_ROOT_PASSWORD="${DB_PASS}"
ADMIN_USERNAME="${ADMIN_USERNAME:-root}"
BRAND_NAME="HiTechCloud Panel"
GITHUB_REPO="${REPO}"
GITHUB_BRANCH="${BRANCH}"
EOF
    chmod 600 "$CRED_FILE"
fi
# An .env written by an earlier build may have bare values; quote any that
# contain whitespace before sourcing, or the shell runs the second word as a
# command and the install stops here.
sed -i -E 's/^([A-Za-z_][A-Za-z0-9_]*)=([^"'"'"'][^\n]*[[:space:]][^\n]*)$/\1="\2"/' "$CRED_FILE"

# shellcheck disable=SC1091
. "$CRED_FILE"

# ---- 4. Host directories and configuration ---------------------------------
step "Creating host configuration"
mkdir -p /etc/hitechcloud/{hitechcloud/conf,hitechcloud/features,hitechcloud/hooks,hitechadmin/config}
mkdir -p /etc/hitechcloud/{emails,ssl/certs,ssl/keys,domains,ftp/users,php/ini,bind9,upgrade}
mkdir -p /etc/hitechcloud/native
mkdir -p /var/log/hitechcloud/{admin,user,native/domains}
mkdir -p /var/lib/hitechcloud/native "$RUNTIME_DIR"
touch /etc/hitechcloud/upgrade/skip_versions

if [ ! -f /etc/hitechcloud/hitechcloud/conf/hitechcloud.config ]; then
cat > /etc/hitechcloud/hitechcloud/conf/hitechcloud.config <<HCCONFIG
[PANEL]
enabled_modules=dashboard,websites,multiweb,services,filemanager,disk_usage,inodes,fix_permissions,malware_scan,trash,ftp,backup_wizard,backups,domains,emails,email_aliases,email_default,email_deliverability,email_export,email_filters,email_import,webmail,php,dns,dynamic_dns,redis,memcached,elasticsearch,opensearch,valkey,varnish,mysql,mysql_conf,mysql_import,mysql_processlist,mysql_root_password,remote_mysql,crons,info,usage,process_manager,ip_blocker,webserver_conf,waf,account,locale,twofa,passkeys,notifications,favorites,sessions,activity,login_history,mcp,api,postgresql,postgresql_conf,postgresql_import,remote_postgresql,python,nodejs,ruby,java,autoinstaller,wordpress,website_builder,terminal,docker
brand_name=HiTechCloud Panel
architecture=native
password_reset=yes
api=on
session_duration=10
session_lifetime=300
autoupdate=on
autopatch=on
server_ip=${SERVER_IP}

[LICENSE]
key=enterprise-opensource-unlimited

[SECURITY]
validate_ip_address_cookie=yes

[DEFAULT]
email=admin@localhost
force_domain=

[SMTP]
mail_security_token=
HCCONFIG
    log "hitechcloud.config created"
else
    # An existing config is the operator's, so it is not rewritten - but a
    # module added by a newer release has to be switched on or its page 404s
    # with nothing to explain why.
    REQUIRED_MODULES="dashboard websites multiweb services filemanager domains php mysql crons info usage account"
    ADDED=""
    for module in $REQUIRED_MODULES; do
        grep -qE "^enabled_modules=.*(^|,)${module}(,|$)" /etc/hitechcloud/hitechcloud/conf/hitechcloud.config && continue
        sed -i -E "s/^(enabled_modules=.*)$/\1,${module}/" /etc/hitechcloud/hitechcloud/conf/hitechcloud.config
        ADDED="${ADDED} ${module}"
    done
    if [ -n "$ADDED" ]; then
        log "hitechcloud.config kept; enabled new modules:${ADDED}"
    else
        log "hitechcloud.config already present - left as is"
    fi
fi

[ -f /etc/hitechcloud/hitechadmin/config/admin.ini ] || cat > /etc/hitechcloud/hitechadmin/config/admin.ini <<'EOF'
[PANEL]
login_blocklimit=20
login_ratelimit=5

[SECURITY]
basic_auth=no
EOF

# Feature sets decide which pages a plan may reach. Without them every gated
# page answers 403 with nothing in the UI to say why, so a missing file here is
# not something to shrug off.
if [ -d "$INSTALL_DIR/configuration/hitechcloud/features" ]; then
    cp -a "$INSTALL_DIR/configuration/hitechcloud/features/." /etc/hitechcloud/hitechcloud/features/
    log "Feature sets installed ($(ls -1 /etc/hitechcloud/hitechcloud/features/*.txt 2>/dev/null | wc -l) sets)"
else
    err "Feature sets not found at ${INSTALL_DIR}/configuration/hitechcloud/features.
  The configuration submodule did not download; run:
    git -C ${INSTALL_DIR} submodule update --init --recursive
  then re-run this installer."
fi

# The rest of the stock configuration the panel and admin read at runtime.
cp -a "$INSTALL_DIR/configuration/hitechcloud/conf/." /etc/hitechcloud/hitechcloud/conf/ 2>/dev/null || true
cp -a "$INSTALL_DIR/hitechcloudpanel/config-admin/." /etc/hitechcloud/hitechadmin/config/ 2>/dev/null || true
cp -a "$INSTALL_DIR/hitechcloudpanel/config-core/." /etc/hitechcloud/hitechcloud/conf/ 2>/dev/null || true
cp -a "$INSTALL_DIR/hitechcloudpanel/config-php/ini/." /etc/hitechcloud/php/ini/ 2>/dev/null || true
cp "$INSTALL_DIR/hitechcloudpanel/features.json" /etc/hitechcloud/hitechadmin/config/features.json 2>/dev/null || true

# ---- 5. hitechcloudcli ----------------------------------------------------------
step "Installing hitechcloudcli"
rm -rf /usr/local/hitechcloudcli
cp -a "$INSTALL_DIR/hitechcloudpanel/hitechcloudcli-scripts" /usr/local/hitechcloudcli
install -m 755 "$INSTALL_DIR/hitechcloudpanel/hitechcloudcli" /usr/local/bin/hitechcloudcli
find /usr/local/hitechcloudcli -name '*.sh' -exec chmod +x {} \; 2>/dev/null || true

# The CLI used to be installed as hitechcli. Leave nothing of it behind: both
# panels now shell out to hitechcloudcli, and a stale hitechcli left on PATH
# would keep answering from whatever version it was last written at.
rm -rf /usr/local/hitechcli /usr/local/bin/hitechcli
log "hitechcloudcli installed (try: hitechcloudcli --help)"

# ---- 6. Native templates ---------------------------------------------------
step "Installing native stack templates"
rm -rf "${RUNTIME_DIR}/configuration-native"
cp -a "$INSTALL_DIR/hitechcloudpanel/configuration-native" "${RUNTIME_DIR}/configuration-native"
log "Templates installed to ${RUNTIME_DIR}/configuration-native"

# ---- 7. Native service stack ----------------------------------------------
step "Installing the native service stack (this takes a few minutes)"
hitechcloudcli native-install ${ENGINES} --php "$DEFAULT_PHP" --with "$WITH_COMPONENTS" \
    --from "${RUNTIME_DIR}/configuration-native" \
    || err "Native stack installation failed. Re-run with: hitechcloudcli native-install ${ENGINES} --debug"

# ---- 8. Panel database -----------------------------------------------------
step "Preparing the panel database"
systemctl enable --now mariadb >/dev/null 2>&1 || systemctl enable --now mysqld >/dev/null 2>&1 || true
mysql -e "CREATE DATABASE IF NOT EXISTS panel CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# The check is for a table, not the database: an interrupted earlier run leaves
# an empty `panel` database behind, and treating that as "already installed"
# gives a panel that cannot store a single user.
if mysql -N -B -e "SELECT 1 FROM panel.users LIMIT 1;" >/dev/null 2>&1; then
    log "Panel schema already loaded"
else
    SCHEMA="$INSTALL_DIR/configuration/mysql/initialize/1.1/plans.sql"
    [ -f "$SCHEMA" ] || err "Panel schema not found at ${SCHEMA}. The configuration submodule did not download; run:
    git -C ${INSTALL_DIR} submodule update --init --recursive
  then re-run this installer."
    mysql panel < "$SCHEMA" || err "Could not load the panel schema from ${SCHEMA}"
    mysql -N -B -e "SELECT 1 FROM panel.users LIMIT 1;" >/dev/null 2>&1 \
        || err "The schema loaded but panel.users is still missing - the schema file may be truncated."
    log "Panel schema loaded"
fi
mysql -e "ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';" >/dev/null 2>&1 || true
# database= matters as much as the credentials here. The CLI's shell scripts
# run plain "mysql -e 'SELECT ... FROM domains'" and rely on root's own client
# defaults to say which schema that is; without it every one of them fails with
# "ERROR 1046 (3D000): No database selected", which surfaces in the panel as
# "Docroot not found for domain" and "Domain already exists".
cat > /root/.my.cnf <<EOF
[client]
user="root"
password="${MYSQL_ROOT_PASSWORD}"
database="panel"
EOF
chmod 600 /root/.my.cnf

# The panel reads its own credentials from a MySQL option file. Debian and
# Ubuntu package MariaDB to read /etc/mysql/, not /etc/my.cnf, so writing this
# file gives the panel its credentials without the database server picking up a
# second configuration.
mkdir -p /etc/hitechcloud/hitechcloud
# Quoted: the MySQL client reads an unquoted '#' as a comment, truncating any
# generated password that happens to contain one.
cat > /etc/hitechcloud/hitechcloud/mysql.cnf <<EOF
[client]
user="root"
password="${MYSQL_ROOT_PASSWORD}"
host="127.0.0.1"
database="panel"
EOF
chmod 600 /etc/hitechcloud/hitechcloud/mysql.cnf
log "Panel database credentials written"

# Redis: the panel talks over a unix socket. The distribution's package does
# not enable one by default.
REDIS_SOCK="/run/redis/redis-server.sock"
if [ -d /etc/redis ]; then
    if ! grep -q "^unixsocket " /etc/redis/redis.conf 2>/dev/null; then
        {
            echo ""
            echo "# Added by HiTechCloud Panel - the panel talks to redis over a socket."
            echo "unixsocket ${REDIS_SOCK}"
            echo "unixsocketperm 770"
        } >> /etc/redis/redis.conf
    fi
    systemctl restart redis-server >/dev/null 2>&1 || systemctl restart redis >/dev/null 2>&1 || true
    log "Redis socket configured at ${REDIS_SOCK}"
fi

# ---- 9. Panel binaries -----------------------------------------------------
step "Installing the panel binaries"

# A released binary is the normal path. A clean server has no Go toolchain, and
# refusing to install because of that left every other step of this installer
# done and the panel itself missing - the machine configured for a product that
# was not there.
release_arch() {
    case "$(uname -m)" in
        x86_64|amd64) echo amd64 ;;
        aarch64|arm64) echo arm64 ;;
        *) echo "" ;;
    esac
}

# download_release_binary <asset-name> <destination>
# Verifies against the release's own SHA256SUMS. An unverifiable download is
# discarded rather than installed: this file is about to run as root.
download_release_binary() {
    local asset="$1" dest="$2" tmp sums want got
    tmp="$(mktemp -d)"
    # shellcheck disable=SC2064
    trap "rm -rf '$tmp'" RETURN

    local base="https://github.com/${REPO}/releases/latest/download"
    local -a auth=()
    # A private repository's release assets are not public either.
    [ -n "${HITECHCLOUD_GITHUB_TOKEN:-}" ] && auth=(-H "Authorization: Bearer ${HITECHCLOUD_GITHUB_TOKEN}")

    curl -fsSL --retry 3 --connect-timeout 15 "${auth[@]}" "${base}/${asset}" -o "${tmp}/${asset}" || return 1
    [ -s "${tmp}/${asset}" ] || return 1

    if curl -fsSL --retry 2 --connect-timeout 15 "${auth[@]}" "${base}/SHA256SUMS" -o "${tmp}/SHA256SUMS" 2>/dev/null; then
        want=$(awk -v a="$asset" '$2 == a || $2 == "*"a { print $1; exit }' "${tmp}/SHA256SUMS")
        if [ -n "$want" ]; then
            got=$(sha256sum "${tmp}/${asset}" | awk '{print $1}')
            [ "$want" = "$got" ] || { warn "checksum mismatch for ${asset}"; return 1; }
        fi
    fi

    install -m 755 "${tmp}/${asset}" "$dest"
}

ARCH="$(release_arch)"
if [ -x "$INSTALL_DIR/hitechcloudpanel/encoded-amd64/hitechcloud" ]; then
    install -m 755 "$INSTALL_DIR/hitechcloudpanel/encoded-amd64/hitechcloud" /usr/local/bin/hitechcloud
elif [ -x "$INSTALL_DIR/hitechcloudpanel/hitechcloud" ]; then
    install -m 755 "$INSTALL_DIR/hitechcloudpanel/hitechcloud" /usr/local/bin/hitechcloud
elif [ -n "$ARCH" ] && download_release_binary "hitechcloud-linux-${ARCH}" /usr/local/bin/hitechcloud; then
    log "Panel binary downloaded from the latest release (${ARCH})"
elif command -v go >/dev/null 2>&1; then
    warn "No released binary available - building from source"
    (cd "$INSTALL_DIR/hitechcloudpanel" && go build -o /usr/local/bin/hitechcloud ./cmd/hitechcloud)
else
    err "No panel binary could be downloaded or built. Install Go and re-run, or fetch
    https://github.com/${REPO}/releases/latest/download/hitechcloud-linux-${ARCH:-amd64}
    to /usr/local/bin/hitechcloud yourself."
fi

if [ -x "$INSTALL_DIR/hitechcloudpanel/hitechcloudadmin/hitechadmin" ]; then
    install -m 755 "$INSTALL_DIR/hitechcloudpanel/hitechcloudadmin/hitechadmin" /usr/local/bin/hitechadmin
elif [ -n "$ARCH" ] && download_release_binary "hitechadmin-linux-${ARCH}" /usr/local/bin/hitechadmin; then
    log "Admin binary downloaded from the latest release (${ARCH})"
elif command -v go >/dev/null 2>&1 && [ -d "$INSTALL_DIR/hitechcloudadmin" ]; then
    (cd "$INSTALL_DIR/hitechcloudadmin" && go build -o /usr/local/bin/hitechadmin ./cmd/hitechadmin) \
        || warn "The admin panel could not be built - the hosting panel works without it"
else
    warn "No admin binary available - the hosting panel works without it, but there will be no admin panel"
fi
log "Binaries installed"

install -m 644 "${RUNTIME_DIR}/configuration-native/systemd/hitechcloud.service" /etc/systemd/system/
[ -x /usr/local/bin/hitechadmin ] && \
    install -m 644 "${RUNTIME_DIR}/configuration-native/systemd/hitechadmin.service" /etc/systemd/system/
cat > /etc/hitechcloud/hitechcloud/conf/panel.env <<EOF
LISTEN_ADDR=:${PANEL_PORT}
HITECHCLOUD_MYSQL_OPTION_FILE=/etc/hitechcloud/hitechcloud/mysql.cnf
HITECHCLOUD_REDIS_SOCKET=${REDIS_SOCK:-/run/redis/redis-server.sock}
EOF
cat > /etc/hitechcloud/hitechadmin/config/admin.env <<EOF
LISTEN_ADDR=:${ADMIN_PORT}
HITECHCLOUD_MYSQL_OPTION_FILE=/etc/hitechcloud/hitechcloud/mysql.cnf
EOF
systemctl daemon-reload
systemctl enable --now hitechcloud >/dev/null 2>&1 || warn "hitechcloud.service did not start - check: journalctl -u hitechcloud"
[ -x /usr/local/bin/hitechadmin ] && { systemctl enable --now hitechadmin >/dev/null 2>&1 || warn "hitechadmin.service did not start"; }

# ---- 9b. The administrator account ------------------------------------------
# Without this the admin panel starts, serves a login page, and accepts nobody:
# its user table is empty and there is no hint anywhere that it should not be.
step "Creating the administrator account"
command -v sqlite3 >/dev/null 2>&1 || {
    if [ "$OS_FAMILY" = debian ]; then apt-get install -y -qq sqlite3 >/dev/null
    else (command -v dnf >/dev/null && dnf install -y -q sqlite) >/dev/null 2>&1 || yum install -y -q sqlite >/dev/null 2>&1; fi
}
ADMIN_DB=/etc/hitechcloud/hitechadmin/users.db
ADMIN_COUNT=$(sqlite3 "$ADMIN_DB" "SELECT COUNT(*) FROM user;" 2>/dev/null || echo 0)
if [ "${ADMIN_COUNT:-0}" -gt 0 ]; then
    log "Administrator account already exists"
elif hitechcloudcli admin new "${ADMIN_USERNAME:-root}" '!system' --super >/dev/null 2>&1; then
    log "Administrator '${ADMIN_USERNAME:-root}' created - it authenticates with this server's own password"
else
    warn "Could not create the administrator account. Create one with:"
    warn "  hitechcloudcli admin new <system-user> '!system' --super"
fi

# ---- 9c. The administrator's own hosting account ----------------------------
# The administrator manages the server from :2087, but has nowhere to put a
# website of their own without one of these. It gets an Unlimited plan: this is
# the person who sets the limits, and applying a customer's disk quota to them
# is the wrong default.
step "The administrator's hosting account"
ADMIN_PLAN="${ADMIN_PLAN:-Unlimited}"

plan_exists() {
    mysql --defaults-extra-file=/etc/hitechcloud/hitechcloud/mysql.cnf -D panel -sN \
        -e "SELECT COUNT(*) FROM plans WHERE name = '$1';" 2>/dev/null
}

if [ "$(plan_exists "$ADMIN_PLAN")" = "0" ]; then
    # 0 means unlimited in every one of these columns.
    hitechcloudcli plan-create name="$ADMIN_PLAN" \
        description="No limits - for the server administrator's own account" \
        emails=0 ftp=0 domains=0 websites=0 disk=0 inodes=0 databases=0 \
        cpu=0 ram=0 bandwidth=0 feature_set=default \
        max_email_quota=0 max_hourly_email=0 >/dev/null 2>&1 &&
        log "Plan '${ADMIN_PLAN}' created" ||
        warn "Could not create the '${ADMIN_PLAN}' plan"
fi

PANEL_ADMIN_USER="${PANEL_ADMIN_USER:-${ADMIN_USERNAME:-root}}"
# "root" is a system account already; a hosting account of that name cannot be
# created and should not be. The panel account gets its own name.
[ "$PANEL_ADMIN_USER" = "root" ] && PANEL_ADMIN_USER="admin"

if id -u "$PANEL_ADMIN_USER" >/dev/null 2>&1; then
    log "Hosting account '${PANEL_ADMIN_USER}' already exists"
else
    PANEL_ADMIN_PASSWORD="$(openssl rand -base64 18 | tr -d '/+=' | head -c 20)"
    if hitechcloudcli user-add "$PANEL_ADMIN_USER" "$PANEL_ADMIN_PASSWORD" \
        "${ADMIN_EMAIL:-admin@$(hostname -f 2>/dev/null || hostname)}" "$ADMIN_PLAN" >/dev/null 2>&1; then
        # Alongside the other credentials this installer generates, mode 0600
        # and outside the repository.
        {
            echo "PANEL_ADMIN_USER=${PANEL_ADMIN_USER}"
            echo "PANEL_ADMIN_PASSWORD=${PANEL_ADMIN_PASSWORD}"
        } >> "$CRED_FILE"
        chmod 600 "$CRED_FILE"
        log "Hosting account '${PANEL_ADMIN_USER}' created on the ${ADMIN_PLAN} plan"
        log "Its password is in ${CRED_FILE}"
    else
        warn "Could not create the administrator's hosting account. Create one with:"
        warn "  hitechcloudcli user-add <name> <password> <email> '${ADMIN_PLAN}'"
    fi
fi

# The dashboard reads every account's disk and inode usage out of a report
# file. Without something writing it, Storage and Inodes show "NaN%".
for unit in hitechcloud-quota.service hitechcloud-quota.timer; do
    [ -f "${RUNTIME_DIR}/configuration-native/systemd/${unit}" ] &&
        install -m 644 "${RUNTIME_DIR}/configuration-native/systemd/${unit}" /etc/systemd/system/
done
systemctl daemon-reload
systemctl enable --now hitechcloud-quota.timer >/dev/null 2>&1 &&
    log "Disk and inode usage will be refreshed every 30 minutes" ||
    warn "hitechcloud-quota.timer could not be enabled - the dashboard's Storage figures will stay empty"

# ---- 10. Podman, for user applications only --------------------------------
step "Installing Podman (user applications only)"
if ! command -v podman >/dev/null 2>&1; then
    if [ "$OS_FAMILY" = debian ]; then
        apt-get install -y -qq podman crun uidmap slirp4netns fuse-overlayfs >/dev/null 2>&1 || warn "Podman could not be installed"
    else
        (command -v dnf >/dev/null && dnf install -y -q podman crun) >/dev/null 2>&1 || warn "Podman could not be installed"
    fi
fi
command -v podman >/dev/null 2>&1 && log "Podman available for the App Store" || warn "Podman missing - App Store applications will be unavailable"

# ---- 11. Multi-WebServer Hosting -------------------------------------------
step "Enabling Multi-WebServer Hosting"
hitechcloudcli native-multiweb enable || warn "Multi-WebServer Hosting could not be enabled - run: hitechcloudcli native-multiweb repair"

# ---- 12. Per-account resource metering -------------------------------------
# The dashboard's CPU and Memory rows and the whole usage-history page are read
# out of /home/<account>/resource_usage.txt. Nothing writes that file unless
# this is scheduled, and the rows sit on "Calculating.." until something does.
#
# This used to be a line in /etc/cron.d/hitechcloud. It is a timer now, like
# AutoSSL, the quota report and the Git deployment poll: one place to look at
# when it last ran, why the last run failed, and how long it took.
step "Scheduling per-account resource metering"
for unit in hitechcloud-usage.service hitechcloud-usage.timer; do
    [ -f "${RUNTIME_DIR}/configuration-native/systemd/${unit}" ] &&
        install -m 644 "${RUNTIME_DIR}/configuration-native/systemd/${unit}" /etc/systemd/system/
done
systemctl daemon-reload

# hitechadmin's System Crons page manages this file and reports it as missing
# when it is not there, so a fresh install still creates it - just without the
# sampler, which is a systemd timer now.
if [ ! -f /etc/cron.d/hitechcloud ]; then
    cat > /etc/cron.d/hitechcloud <<'CRON'
SHELL=/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
CRON
    chmod 644 /etc/cron.d/hitechcloud
fi

# An upgrade from a release that scheduled the sampler from cron would
# otherwise sample twice a minute, each run halving the other's measurement
# window. Only that one line is taken out.
sed -i '\|hitechcloudcli native-usage collect|d' /etc/cron.d/hitechcloud

systemctl enable --now hitechcloud-usage.timer >/dev/null 2>&1 &&
    log "CPU and memory will be sampled for every account once a minute" ||
    warn "hitechcloud-usage.timer could not be enabled - the dashboard's CPU and Memory rows will stay at 0%"

# ---- 13. Summary -----------------------------------------------------------
echo
echo -e "${GREEN}╔══════════════════════════════════════════════════════════╗${NC}"
echo -e "${GREEN}║        HiTechCloud Panel ${VERSION} installed (native)         ║${NC}"
echo -e "${GREEN}╚══════════════════════════════════════════════════════════╝${NC}"
echo
printf '  %-14s https://%s:%s\n' "Panel"    "${SERVER_IP}" "${PANEL_PORT}"
[ -x /usr/local/bin/hitechadmin ] && printf '  %-14s https://%s:%s\n' "Admin" "${SERVER_IP}" "${ADMIN_PORT}"
printf '  %-14s %s\n' "Username" "${ADMIN_USERNAME:-root}"
printf '  %-14s %s\n' "Password" "this server's own ${ADMIN_USERNAME:-root} password"
printf '  %-14s %s\n' "Credentials" "${CRED_FILE} (database only; not the admin password)"
echo
echo "  Architecture:"
hitechcloudcli native-multiweb status 2>/dev/null | sed 's/^/  /'
echo
echo "  Useful commands:"
echo "    hitechcloudcli native-multiweb status        architecture and service state"
echo "    hitechcloudcli native-engine set <d> apache  give one website its own WebEngine"
echo "    hitechcloudcli native-ssl issue <domain>     get a Let's Encrypt certificate"
echo "    hitechcloudcli native-service list           every backend service"
echo
