#!/bin/bash
set -e

# Global variables
OS_FAMILY=""
OS_NAME=""
OS_VERSION=""
N8N_PORT="5678"
N8N_VOLUME="n8n_data"
N8N_CONTAINER="n8n"

# Detect operating system and version
detect_os() {
    if [ -f /etc/os-release ]; then
        . /etc/os-release
        OS_NAME=$ID
        OS_VERSION=$VERSION_ID

        case $OS_NAME in
            ubuntu)
                if [[ "$OS_VERSION" == "22.04" || "$OS_VERSION" == "24.04" ]]; then
                    OS_FAMILY="debian"
                else
                    echo "Unsupported Ubuntu version: $OS_VERSION"
                    exit 1
                fi
                ;;
            debian)
                if [[ "$OS_VERSION" == "11" || "$OS_VERSION" == "12" || "$OS_VERSION" == "13" ]]; then
                    OS_FAMILY="debian"
                else
                    echo "Unsupported Debian version: $OS_VERSION"
                    exit 1
                fi
                ;;
            almalinux|rocky)
                if [[ "$OS_VERSION" =~ ^(8|9|10) ]]; then
                    OS_FAMILY="rhel"
                else
                    echo "Unsupported $OS_NAME version: $OS_VERSION"
                    exit 1
                fi
                ;;
            centos)
                if [[ "$OS_VERSION" =~ ^(9|10) ]]; then
                    OS_FAMILY="rhel"
                else
                    echo "Unsupported CentOS version: $OS_VERSION"
                    exit 1
                fi
                ;;
            *)
                echo "Unsupported operating system: $OS_NAME"
                exit 1
                ;;
        esac
    else
        echo "Cannot detect operating system"
        exit 1
    fi
}

# Configure non-interactive mode
configure_noninteractive() {
    export DEBIAN_FRONTEND=noninteractive
    export NEEDRESTART_MODE=a

    if [ "$OS_FAMILY" = "debian" ]; then
        echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections >/dev/null 2>&1
        echo 'grub-pc grub-pc/install_devices_empty boolean true' | debconf-set-selections >/dev/null 2>&1
        echo 'grub-pc grub-pc/install_devices string /dev/sda' | debconf-set-selections >/dev/null 2>&1
        echo 'libc6 libraries/restart-without-asking boolean true' | debconf-set-selections >/dev/null 2>&1
    fi
}

# Install Docker
install_docker() {
    if command -v docker >/dev/null 2>&1; then
        echo "Docker already installed, skipping."
        return
    fi

    if [ "$OS_FAMILY" = "debian" ]; then
        apt-get update >/dev/null 2>&1
        apt-get install -y ca-certificates curl gnupg >/dev/null 2>&1

        mkdir -p /etc/apt/keyrings >/dev/null 2>&1
        curl -fsSL https://download.docker.com/linux/${OS_NAME}/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg >/dev/null 2>&1
        chmod a+r /etc/apt/keyrings/docker.gpg >/dev/null 2>&1

        echo \
            "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
            https://download.docker.com/linux/${OS_NAME} \
            $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
            tee /etc/apt/sources.list.d/docker.list >/dev/null 2>&1

        apt-get update >/dev/null 2>&1
        apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null 2>&1

    elif [ "$OS_FAMILY" = "rhel" ]; then
        if command -v dnf >/dev/null 2>&1; then
            PKG_MANAGER="dnf"
        else
            PKG_MANAGER="yum"
        fi

        $PKG_MANAGER install -y yum-utils >/dev/null 2>&1
        yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo >/dev/null 2>&1
        $PKG_MANAGER install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin >/dev/null 2>&1
    fi
}

# Enable and start Docker service
start_docker() {
    systemctl enable docker >/dev/null 2>&1
    systemctl start docker >/dev/null 2>&1

    # Wait for Docker daemon to be ready
    local retries=10
    until docker info >/dev/null 2>&1 || [ $retries -eq 0 ]; do
        sleep 2
        retries=$((retries - 1))
    done

    if ! docker info >/dev/null 2>&1; then
        echo "Error: Docker daemon failed to start"
        exit 1
    fi
}

# Create Docker volume and run N8N container
install_n8n() {
    # Create named volume for persistent data
    docker volume create "$N8N_VOLUME" >/dev/null 2>&1

    # Pull latest N8N image
    docker pull docker.n8n.io/n8nio/n8n:latest >/dev/null 2>&1

    # Run N8N container
    docker run -d \
        --name "$N8N_CONTAINER" \
        --restart always \
        -p "${N8N_PORT}:5678" \
        -v "${N8N_VOLUME}:/home/node/.n8n" \
        -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true \
        -e N8N_RUNNERS_ENABLED=true \
        -e N8N_SECURE_COOKIE=false \
        docker.n8n.io/n8nio/n8n:latest >/dev/null 2>&1
}

# Verify N8N container is running
verify_installation() {
    if ! command -v docker >/dev/null 2>&1; then
        echo "Error: Docker installation failed"
        exit 1
    fi

    local retries=15
    until docker ps --filter "name=${N8N_CONTAINER}" --filter "status=running" | grep -q "$N8N_CONTAINER" || [ $retries -eq 0 ]; do
        sleep 2
        retries=$((retries - 1))
    done

    if ! docker ps --filter "name=${N8N_CONTAINER}" --filter "status=running" | grep -q "$N8N_CONTAINER"; then
        echo "Error: N8N container failed to start"
        docker logs "$N8N_CONTAINER" >/dev/null 2>&1 || true
        exit 1
    fi
}

# Update MOTD with N8N information
update_motd() {
    N8N_VER=$(docker exec "$N8N_CONTAINER" n8n --version 2>/dev/null || echo "latest")
    INSTALL_DATE=$(date '+%Y-%m-%d %H:%M:%S')

    # Attempt to get the server's primary IP
    SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}')

    cat > /etc/motd <<EOF
╔═══════════════════════════════════════════════════════════════════╗
║                   N8N - Installation Complete                    ║
╚═══════════════════════════════════════════════════════════════════╝

N8N Version:     $N8N_VER
Installed:       $INSTALL_DATE
Container:       $N8N_CONTAINER (always restart)
Data Volume:     $N8N_VOLUME
Port:            $N8N_PORT

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Access N8N:
  • Web UI:       http://${SERVER_IP}:${N8N_PORT}
  • First visit will prompt you to create an owner account.

Quick Commands:
  • Check status:  docker ps -f name=${N8N_CONTAINER}
  • View logs:     docker logs -f ${N8N_CONTAINER}
  • Stop N8N:      docker stop ${N8N_CONTAINER}
  • Start N8N:     docker start ${N8N_CONTAINER}
  • Restart N8N:   docker restart ${N8N_CONTAINER}
  • Update N8N:    docker pull docker.n8n.io/n8nio/n8n:latest && \\
                   docker stop ${N8N_CONTAINER} && \\
                   docker rm ${N8N_CONTAINER} && \\
                   (re-run the docker run command above)

Documentation:
  • N8N Docs:      https://docs.n8n.io/
  • Docker Setup:  https://docs.n8n.io/hosting/installation/docker/

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
EOF
}

# Cleanup function
cleanup() {
    rm -f /home/n8n.sh

    history -c >/dev/null 2>&1
    cat /dev/null > ~/.bash_history >/dev/null 2>&1
}

# Main function
main() {
    if [ "$EUID" -ne 0 ]; then
        echo "Error: This script must be run as root"
        exit 1
    fi

    detect_os
    configure_noninteractive
    install_docker
    start_docker
    install_n8n
    verify_installation
    update_motd
    cleanup

    wall "The installation of N8N is complete. Please see the motd for more details"
}

# Execute main function
main "$@"
