#!/usr/bin/env bash
set -euo pipefail

readonly CONTROL_PLANE="${MFCORE_CONTROL_PLANE:-https://cms.mf-core.com}"
readonly DEFAULT_IMAGE="${MFCORE_IMAGE:-cms.mf-core.com/mfcore/cms:latest}"
readonly DEFAULT_INSTALL_DIR="/opt/mfcore"
readonly APP_UID=1000
readonly APP_GID=1000

fail() { printf 'MF Core installer: %s\n' "$*" >&2; exit 1; }
require() { command -v "$1" >/dev/null 2>&1 || fail "Required command not found: $1"; }

[ "${EUID}" -eq 0 ] || fail "Run this installer with sudo."
for command in curl docker openssl; do require "${command}"; done
docker compose version >/dev/null 2>&1 || fail "The Docker Compose plugin is required."
[ "$(uname -s)" = "Linux" ] || fail "The first MF Core release supports Linux only."
[ "$(uname -m)" = "x86_64" ] || fail "The first MF Core release supports amd64 hosts only."

read -r -p "Installation directory [${DEFAULT_INSTALL_DIR}]: " INSTALL_DIR
INSTALL_DIR="${INSTALL_DIR:-${DEFAULT_INSTALL_DIR}}"
[[ "${INSTALL_DIR}" =~ ^/[^[:space:]]*$ && "${INSTALL_DIR}" != "/" ]] || fail "Use an absolute installation path without spaces."
[ ! -e "${INSTALL_DIR}/.env" ] || fail "MF Core is already installed. Use Docker Compose in ${INSTALL_DIR} to manage it."

read -r -p "CMS hostname (for example cms.example.com): " cms_domain
cms_domain="${cms_domain,,}"
[[ "${cms_domain}" =~ ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)*[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$ ]] || fail "Enter a valid hostname."
read -r -p "Local port [17384]: " published_port
published_port="${published_port:-17384}"
[[ "${published_port}" =~ ^[0-9]+$ ]] && [ "${published_port}" -ge 1 ] && [ "${published_port}" -le 65535 ] || fail "Enter a port from 1 to 65535."
read -r -p "Administrator username [admin]: " admin_username
admin_username="${admin_username:-admin}"
[[ "${admin_username}" =~ ^[A-Za-z0-9._-]{3,80}$ ]] || fail "Use 3-80 letters, numbers, dots, underscores, or dashes."
read -r -s -p "Initial administrator password (12+ safe characters): " admin_password
printf '\n'
[[ "${admin_password}" =~ ^[A-Za-z0-9._@%+=:-]{12,128}$ ]] || fail "Use 12-128 letters, numbers, or ._@%+=:- characters."

install -d -m 0755 "${INSTALL_DIR}"
install -d -o "${APP_UID}" -g "${APP_GID}" -m 0750 /var/lib/mfcore/data /var/lib/mfcore/uploads
curl -fsS "${CONTROL_PLANE}/compose.yaml" -o "${INSTALL_DIR}/compose.yaml"
chmod 0644 "${INSTALL_DIR}/compose.yaml"
umask 077
{
  printf 'MFCORE_IMAGE=%s\n' "${DEFAULT_IMAGE}"
  printf 'CMS_DOMAIN=%s\n' "${cms_domain}"
  printf 'PUBLISHED_PORT=%s\n' "${published_port}"
  printf 'ADMIN_USERNAME=%s\n' "${admin_username}"
  printf 'ADMIN_PASSWORD=%s\n' "${admin_password}"
  printf 'SESSION_SECRET=%s\n' "$(openssl rand -hex 48)"
  printf 'LICENCE_STORAGE_SECRET=%s\n' "$(openssl rand -hex 48)"
} > "${INSTALL_DIR}/.env"
chmod 0600 "${INSTALL_DIR}/.env"

docker compose --project-directory "${INSTALL_DIR}" --env-file "${INSTALL_DIR}/.env" -f "${INSTALL_DIR}/compose.yaml" pull
docker compose --project-directory "${INSTALL_DIR}" --env-file "${INSTALL_DIR}/.env" -f "${INSTALL_DIR}/compose.yaml" up -d --wait

printf '\nMF Core is running on http://127.0.0.1:%s\n' "${published_port}"
printf 'Open https://%s/admin after configuring your reverse proxy, then enter the licence key.\n\n' "${cms_domain}"
printf 'Update later with:\n  cd %s\n  sudo docker compose pull\n  sudo docker compose up -d --wait\n\n' "${INSTALL_DIR}"
printf 'Nginx example:\nserver {\n  server_name %s;\n  location / {\n    proxy_pass http://127.0.0.1:%s;\n    proxy_set_header Host $host;\n    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n    proxy_set_header X-Forwarded-Proto $scheme;\n  }\n}\n\n' "${cms_domain}" "${published_port}"
printf 'Caddy example:\n%s {\n  reverse_proxy 127.0.0.1:%s\n}\n' "${cms_domain}" "${published_port}"
