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

# Ensure script is run as root (required for apt + /etc)
if [[ "$EUID" -ne 0 ]]; then
  echo "Please run as root (or use sudo)." >&2
  exit 1
fi

# what this script needs to do:

# request all install parameters needed from user
# ---- User input ----
read -rp "Admin email: " adminemail < /dev/tty
read -rsp "Admin password: " adminpass < /dev/tty
echo
read -rp "Timezone (e.g. Europe/Amsterdam): " timezone < /dev/tty
read -rp "Domain (e.g. example.com): " domain < /dev/tty

# Public IP (tries multiple services)
publicip="$(curl -fsS https://api.ipify.org || curl -fsS https://ifconfig.me || echo "UNKNOWN")"

# Local IP (first non-loopback)
localip="$(hostname -I | awk '{print $1}')"

# generate random passwords for DB hosts and other secrets

# ---- Random generators ----
rand_hex() { openssl rand -hex 24; }
rand_b64() { openssl rand -base64 32; }

ownclouddbpass="$(rand_hex)"
ownclouddbrootpass="$(rand_hex)"
convertxJWT="$(rand_hex)"
bookstackkey="$(rand_b64)"        # base64 as requested
bookstackdbpass="$(rand_hex)"
bookstackdbrootpass="$(rand_hex)"
onlyofficeJWT="$(rand_hex)"

# ---- Debug print (optional — remove in production) ----
echo "Configuration summary:"
printf "%-25s %s\n" \
  "Admin email:" "$adminemail" \
  "Timezone:" "$timezone" \
  "Domain:" "$domain" \
  "Public IP:" "$publicip" \
  "Local IP:" "$localip"





# install docker
echo "Updating apt and installing prerequisites..."
apt update
apt install -y ca-certificates curl

echo "Setting up Docker GPG key..."
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
  -o /etc/apt/keyrings/docker.asc
chmod a+r /etc/apt/keyrings/docker.asc

echo "Adding Docker apt repository..."
. /etc/os-release

cat > /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: ${UBUNTU_CODENAME:-$VERSION_CODENAME}
Components: stable
Signed-By: /etc/apt/keyrings/docker.asc
EOF

echo "Updating apt and installing Docker..."
apt update
apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-compose-plugin

echo "Docker installation complete."
docker --version




# install dockge
mkdir -p /opt/stacks /opt/dockge
cd /opt/dockge

# Download your compose.yaml
curl "https://dockge.kuma.pet/compose.yaml?port=5001&stacksPath=%2Fopt%2Fstacks" --output compose.yaml

# Start the Server
# docker compose up -d

# create directories in /opt/stacks for containers
# directories needed: npm,dozzle,kuma,browser,site,owncloud,vaultwarden,wireguard,convertx,it-tools,bookstack,jellyfin,onlyoffice,downloader,dashboard,pihole
cd /opt/stacks
mkdir /opt/stacks/{npm,dozzle,kuma,browser,site,owncloud,vaultwarden,wireguard,convertx,it-tools,bookstack,jellyfin,onlyoffice,downloader,dashboard,pihole}
# write docker setup for each component to correct directories

# Nginx Proxy:
# needed: compose.yml, auto-generated proxy host files
# variables needed: domain, admin email, admin pass
cat > /opt/stacks/npm/compose.yml <<EOF
services:
  app:
    image: jc21/nginx-proxy-manager:latest
    restart: unless-stopped
    networks:
      - dockge_default
    ports:
      # These ports are in format <host-port>:<container-port>
      - 80:80 # Public HTTP Port
      - 443:443 # Public HTTPS Port
      - 81:81 # Admin Web Port
      # Add any other Stream port you want to expose
      # - '21:21' # FTP

    environment:
      TZ: $timezone
      # Uncomment this if you want to change the location of
      # the SQLite DB file within the container
      # DB_SQLITE_FILE: "/data/database.sqlite"

      # Uncomment this if IPv6 is not enabled on your host
      # DISABLE_IPV6: 'true'

    volumes:
      - ./data:/data
      - ./letsencrypt:/etc/letsencrypt
networks:
  dockge_default:
    external: true



EOF

# Uptime Kuma:
# needed: compose.yml
# variables needed: admin email, admin pass
cat > /opt/stacks/kuma/compose.yml <<EOF

services:
  uptime-kuma:
    image: louislam/uptime-kuma:2
    restart: unless-stopped
    volumes:
      - ./data:/app/data
    networks:
      - dockge_default
    dns:
      - 1.1.1.1
      - 8.8.8.8
networks:
  dockge_default:
    external: true
    
EOF

# File Browser:
# needed: compose.yml 
# variables needed: admin email, admin pass
cat > /opt/stacks/browser/compose.yml <<EOF

services:
  browser:
    image: filebrowser/filebrowser
    privileged: true
    container_name: browser
    user: root
    networks:
      - dockge_default
    volumes:
      - /opt/stacks:/srv/stacks
      - ./filebrowser.db:/database.db
    restart: unless-stopped
networks:
  dockge_default:
    external: true

EOF

# Main Site:
# needed: compose.yml
cat > /opt/stacks/site/compose.yml <<EOF
services:
  site:
    image: lscr.io/linuxserver/nginx:latest
    restart: unless-stopped
    user: root
    networks:
      - dockge_default
    environment:
      TZ: $timezone
    volumes:
      - ./config:/config
networks:
  dockge_default:
    external: true
EOF


# owncloud:
# needed: compose.yml, additional config?
# variables needed: admin email, admin pass
cat > /opt/stacks/owncloud/compose.yml <<EOF

services:
  owncloud_server:
    image: owncloud/server:latest
    container_name: owncloud_server
    restart: always
    networks:
      - dockge_default
    depends_on:
      - owncloud_db
      - owncloud_redis
    environment:
      OWNCLOUD_DOMAIN: https://cloud.$domain
      OWNCLOUD_TRUSTED_DOMAINS: localhost, cloud.$domain
      OWNCLOUD_DB_TYPE: mysql
      OWNCLOUD_DB_NAME: owncloud
      OWNCLOUD_DB_USERNAME: owncloud
      OWNCLOUD_DB_PASSWORD: $ownclouddbpass
      OWNCLOUD_DB_HOST: owncloud_db
      OWNCLOUD_ADMIN_USERNAME: $adminemail
      OWNCLOUD_ADMIN_PASSWORD: $adminpass
      OWNCLOUD_MYSQL_UTF8MB4: true
      OWNCLOUD_REDIS_ENABLED: true
      OWNCLOUD_REDIS_HOST: owncloud_redis
    healthcheck:
      test: ["CMD", "/usr/bin/healthcheck"]
      interval: 30s
      timeout: 10s
      retries: 5
    volumes:
      - ./data:/mnt/data

  owncloud_db:
    image: mariadb:10.11 # minimum required ownCloud version is 10.9
    container_name: owncloud_db
    restart: always
    networks:
      - dockge_default
    environment:
      - MYSQL_ROOT_PASSWORD=$ownclouddbrootpass
      - MYSQL_USER=owncloud
      - MYSQL_PASSWORD=$ownclouddbpass
      - MYSQL_DATABASE=owncloud
      - MARIADB_AUTO_UPGRADE=1
    command: ["--max-allowed-packet=128M", "--innodb-log-file-size=64M"]
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-u", "root", "--password=owncloud"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - ./mysql:/var/lib/mysql

  owncloud_redis:
    image: redis:6
    container_name: owncloud_redis
    restart: always
    networks:
      - dockge_default
    command: ["--databases", "1"]
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - ./redis:/data
networks:
  dockge_default:
    external: true
EOF

# vaultwarden:
# needed: compose.yml
cat > /opt/stacks/vaultwarden/compose.yml <<EOF

services:
  vaultwarden:
    container_name: vaultwarden
    image: vaultwarden/server:latest
    restart: unless-stopped
    volumes:
      - ./data:/data/
    networks:
      - dockge_default
networks:
  dockge_default:
    external: true
    
EOF



# wireguard-easy:
# needed: compose.yml
# variables needed: admin email, admin pass
cat > /opt/stacks/wireguard/compose.yml <<EOF

services:
  wireguard:
    container_name: wireguard
    environment:
      WG_HOST: $publicip
      PASSWORD: $adminpass
    volumes:
      - ./wireguard:/etc/wireguard
    ports:
      -51820/udp
    networks:
      - dockge_default
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
      - net.ipv4.ip_forward=1
    restart: unless-stopped
    image: weejewel/wg-easy
networks:
  dockge_default:
    external: true
    
EOF

# convertx:
# needed: compose.yml
cat > /opt/stacks/convertx/compose.yml <<EOF

services:
  convertx:
    image: ghcr.io/c4illin/convertx
    container_name: convertx
    restart: unless-stopped
    networks:
      - dockge_default
    environment:
      JWT_SECRET: $convertxJWT
      HTTP_ALLOWED: true
      ALLOW_UNAUTHENTICATED: true
      ACCOUNT_REGISTRATION: false
    volumes:
      - ./data:/app/data
networks:
  dockge_default:
    external: true
    
EOF

# it-tools:
# needed: compose.yml
cat > /opt/stacks/it-tools/compose.yml <<EOF

services:
  it-tools:
    container_name: it-tools
    restart: unless-stopped
    networks:
      - dockge_default
    image: corentinth/it-tools:latest
networks:
  dockge_default:
    external: true


EOF

# bookstack:
# needed: compose.yml
# variables needed: admin email, admin pass
cat > /opt/stacks/bookstack/compose.yml <<EOF

services:
  bookstack:
    image: lscr.io/linuxserver/bookstack:latest
    container_name: bookstack
    environment:
      TZ: $timezone
      APP_URL: https://docs.$domain
      APP_KEY: base64:$bookstackkey
      DB_HOST: bookstack_db
      DB_PORT: 3306
      DB_DATABASE: bookstack
      DB_USERNAME: bookstack
      DB_PASSWORD: $bookstackdbpass
    volumes:
       - ./config:/config
    networks:
      - dockge_default
    restart: unless-stopped
  bookstack_db:
    image: lscr.io/linuxserver/mariadb:latest
    container_name: bookstack_db
    networks:
      - dockge_default
    environment:
      TZ: $timezone
      MYSQL_ROOT_PASSWORD: $bookstackdbrootpass
      MYSQL_DATABASE: bookstack
      MYSQL_USER: bookstack
      MYSQL_PASSWORD: $bookstackdbpass
    restart: unless-stopped
networks:
  dockge_default:
    external: true


EOF

# jellyfin:
# needed: compose.yml
# variables needed: admin email, admin pass

cat > /opt/stacks/jellyfin/compose.yml <<EOF

services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    user: root
    networks:
     - dockge_default
    volumes:
     - ./config:/config
     - ./cache:/cache
     - ./media:/media:ro
     - ./fonts:/usr/local/share/fonts/custom:ro
    restart: unless-stopped
    environment:
      JELLYFIN_PublishedServerUrl: https://video.$domain
      TZ: $timezone
networks:
  dockge_default:
    external: true
EOF

# onlyoffice:
# needed: compose.yml
cat > /opt/stacks/onlyoffice/compose.yml <<EOF
services:
  documentserver:
    stdin_open: true
    tty: true
    restart: always
    networks:
      - dockge_default
    image: onlyoffice/documentserver
    dns:
      - 1.1.1.1
      - 8.8.8.8
    environment:
      JWT_SECRET: $onlyofficeJWT
      JWT_IN_BODY: true
networks:
  dockge_default:
    external: true

EOF

# dashboard:
# needed: compose.yml
cat > /opt/stacks/dashboard/compose.yml <<EOF

services:
  dashboard:
    image: lscr.io/linuxserver/heimdall:latest
    container_name: dashboard
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=$timezone
      - ALLOW_INTERNAL_REQUESTS=false #optional
      - APP_NAME=Home
    volumes:
      - ./Heimdall:/config
    networks:
      - dockge_default
    restart: unless-stopped
networks:
  dockge_default:
    external: true

EOF
    
# dozzle
cat >/opt/stacks/dozzle/compose.yml <<EOF
services:
  dozzle:
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    networks:
      - dockge_default
    image: amir20/dozzle:latest
    restart: always
networks:
  dockge_default:
    external: true

EOF

# pihole
cat >/opt/stacks/pihole/compose.yml <<EOF
services:
  pihole:
    container_name: pihole
    image: pihole/pihole:latest
    dns:
      - 1.1.1.1
    ports:
      - 53:53/tcp
      - 53:53/udp
    environment:
      TZ: Europe/Amsterdam
      FTLCONF_WEBSERVER_API_PASSWORD: z5fGWz2i0q
    volumes:
      - ./config:/etc/pihole
      - ./dns:/etc/dnsmasq.d
    cap_add:
      - NET_ADMIN
    restart: unless-stopped
    networks:
      - dockge_default
networks:
  dockge_default:
    external: true
EOF

    

# install mailcow to /opt/stacks/mailcow so it shows up in dockge
apt install -y git openssl curl gawk coreutils grep jq
umask 0022
#cd /opt/stacks
#git clone https://github.com/mailcow/mailcow-dockerized mailcow
#cd /opt/stacks/mailcow
#bash ./generate_config.sh < /dev/tty




# install youtube downloader to /opt/stacks/downloader so it shows up in dockge

cd /opt/stacks
git clone https://github.com/trantienloi2404/youtube-downloader.git downloader


cd /opt/dockge
docker compose up -d

#disable stub listener

echo "DNSStubListener=no" | tee -a /etc/systemd/resolved.conf

echo ""
echo ""
echo ""
echo "you can now access the dockge GUI interface at $localip:5001 and the proxy interface at $localip:81 once you start it from Dockge. be sure to forward ports 80, 443 and 51820 to $localip in your router settings"
echo "please reboot before further setup"



