#!/bin/bash

#############################################################
#### Mattermost Server Install Script                    ####
#### Bare-metal deployment with PostgreSQL and nginx      ####
####                                                     ####
#### Author: Phil Connor                                 ####
#### Contact: contact@mylinux.work                       ####
#### License: MIT                                        ####
#### Version: 1.0                                        ####
####                                                     ####
#### Usage: sudo ./install-mattermost.sh                 ####
####        sudo ./install-mattermost.sh --help          ####
#############################################################

set -euo pipefail

# ============================================================================
# CONFIGURATION (edit these before running)
# ============================================================================

MATTERMOST_VERSION="10.6.1"
DOMAIN="mattermost.example.com"
DB_NAME="mattermost"
DB_USER="mmuser"
DB_PASS=""
MM_USER="mattermost"
MM_DIR="/opt/mattermost"
DATA_DIR="/opt/mattermost/data"
NGINX_CONF=true

# ============================================================================
# INTERNAL
# ============================================================================

readonly VERSION="1.0"
readonly SCRIPT_NAME="${0##*/}"

OS_ID=""
OS_FAMILY=""
PKG_MGR=""

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

# ============================================================================
# HELPER FUNCTIONS
# ============================================================================

log_info()  { echo -e "${GREEN}[INFO]${NC} $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
log_step()  { echo -e "${CYAN}[STEP]${NC} $*"; }

show_usage() {
    cat <<EOF
Usage: sudo $SCRIPT_NAME [OPTIONS]

Installs Mattermost Server with PostgreSQL and nginx reverse proxy
on Ubuntu/Debian or RHEL/AlmaLinux/Rocky Linux.

OPTIONS:
    --version VER       Mattermost version to install (default: $MATTERMOST_VERSION)
    --domain FQDN       Server domain name (default: $DOMAIN)
    --db-pass PASS      PostgreSQL password for mmuser (default: random)
    --no-nginx          Skip nginx reverse proxy configuration
    -h, --help          Show this help message

EXAMPLES:
    sudo $SCRIPT_NAME
    sudo $SCRIPT_NAME --version 10.6.1 --domain chat.example.com
    sudo $SCRIPT_NAME --domain mm.corp.local --no-nginx
    sudo $SCRIPT_NAME --db-pass 'MySecureP@ss'

EOF
    exit 0
}

parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            --version)    MATTERMOST_VERSION="$2"; shift 2 ;;
            --domain)     DOMAIN="$2"; shift 2 ;;
            --db-pass)    DB_PASS="$2"; shift 2 ;;
            --no-nginx)   NGINX_CONF=false; shift ;;
            -h|--help)    show_usage ;;
            *)            log_error "Unknown option: $1"; show_usage ;;
        esac
    done
}

check_root() {
    if [[ $EUID -ne 0 ]]; then
        log_error "This script must be run as root (sudo)"
        exit 1
    fi
}

# ============================================================================
# OS DETECTION
# ============================================================================

detect_os() {
    if [[ -f /etc/os-release ]]; then
        . /etc/os-release
        OS_ID="$ID"
    else
        log_error "Cannot detect OS — /etc/os-release not found"
        exit 1
    fi

    case "$OS_ID" in
        ubuntu|debian)
            OS_FAMILY="debian"
            PKG_MGR="apt"
            ;;
        rhel|rocky|almalinux|centos)
            OS_FAMILY="rhel"
            PKG_MGR="dnf"
            if ! command -v dnf &>/dev/null; then
                PKG_MGR="yum"
            fi
            ;;
        *)
            log_error "Unsupported OS: $OS_ID"
            exit 1
            ;;
    esac

    log_info "Detected OS: $PRETTY_NAME (package manager: $PKG_MGR)"
}

# ============================================================================
# STEP 1: INSTALL DEPENDENCIES
# ============================================================================

install_dependencies() {
    log_step "Installing dependencies..."

    case "$OS_FAMILY" in
        debian)
            apt-get update -qq
            apt-get install -y -qq postgresql postgresql-contrib nginx curl jq
            ;;
        rhel)
            $PKG_MGR install -y -q postgresql-server postgresql nginx curl jq
            # Initialize PostgreSQL if not already done
            if [[ ! -d /var/lib/pgsql/data ]] || [[ -z "$(ls -A /var/lib/pgsql/data 2>/dev/null)" ]]; then
                log_info "Initializing PostgreSQL database..."
                postgresql-setup --initdb
            fi
            # Enable and start PostgreSQL
            systemctl enable postgresql
            systemctl start postgresql
            ;;
    esac

    # Ensure PostgreSQL is running on Debian-based as well
    if [[ "$OS_FAMILY" == "debian" ]]; then
        systemctl enable postgresql
        systemctl start postgresql
    fi

    log_info "Dependencies installed"
}

# ============================================================================
# STEP 2: CONFIGURE POSTGRESQL
# ============================================================================

configure_database() {
    log_step "Configuring PostgreSQL database..."

    # Generate random password if not provided
    if [[ -z "$DB_PASS" ]]; then
        DB_PASS=$(openssl rand -base64 24 | tr -d '/+=')
        log_info "Generated random database password"
    fi

    # Create user if not exists
    if sudo -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='$DB_USER'" | grep -q 1; then
        log_warn "PostgreSQL user '$DB_USER' already exists — updating password"
        sudo -u postgres psql -c "ALTER USER $DB_USER WITH PASSWORD '$DB_PASS';"
    else
        sudo -u postgres psql -c "CREATE USER $DB_USER WITH PASSWORD '$DB_PASS';"
        log_info "Created PostgreSQL user: $DB_USER"
    fi

    # Create database if not exists
    if sudo -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1; then
        log_warn "Database '$DB_NAME' already exists"
    else
        sudo -u postgres psql -c "CREATE DATABASE $DB_NAME OWNER $DB_USER;"
        log_info "Created database: $DB_NAME"
    fi

    sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE $DB_NAME TO $DB_USER;"

    # Ensure md5/scram-sha-256 auth for local connections on RHEL
    if [[ "$OS_FAMILY" == "rhel" ]]; then
        local pg_hba
        pg_hba=$(sudo -u postgres psql -tAc "SHOW hba_file;")
        if [[ -f "$pg_hba" ]] && grep -q 'ident' "$pg_hba"; then
            log_info "Updating pg_hba.conf to allow password authentication..."
            sed -i 's/^\(local.*all.*all.*\)ident/\1md5/' "$pg_hba"
            sed -i 's/^\(host.*all.*all.*127\.0\.0\.1\/32.*\)ident/\1md5/' "$pg_hba"
            sed -i 's/^\(host.*all.*all.*::1\/128.*\)ident/\1md5/' "$pg_hba"
            systemctl restart postgresql
        fi
    fi

    log_info "PostgreSQL configured"
}

# ============================================================================
# STEP 3: CREATE SYSTEM USER
# ============================================================================

create_system_user() {
    log_step "Creating system user..."

    if id "$MM_USER" &>/dev/null; then
        log_warn "System user '$MM_USER' already exists"
    else
        useradd --system --no-create-home --shell /usr/sbin/nologin "$MM_USER"
        log_info "Created system user: $MM_USER"
    fi
}

# ============================================================================
# STEP 4: DOWNLOAD AND EXTRACT MATTERMOST
# ============================================================================

download_mattermost() {
    log_step "Downloading Mattermost v${MATTERMOST_VERSION}..."

    local download_url="https://releases.mattermost.com/${MATTERMOST_VERSION}/mattermost-${MATTERMOST_VERSION}-linux-amd64.tar.gz"
    local tmp_file="/tmp/mattermost-${MATTERMOST_VERSION}.tar.gz"

    if [[ -d "$MM_DIR" ]] && [[ -f "$MM_DIR/bin/mattermost" ]]; then
        local existing_version
        existing_version=$("$MM_DIR/bin/mattermost" version 2>/dev/null | grep -oP 'Version:\s*\K[\d.]+' || echo "unknown")
        log_warn "Mattermost already installed at $MM_DIR (version: $existing_version)"
        log_warn "Skipping download — remove $MM_DIR to reinstall"
        return 0
    fi

    curl -fSL -o "$tmp_file" "$download_url"
    log_info "Downloaded: $download_url"

    # Extract to /opt (creates /opt/mattermost)
    tar -xzf "$tmp_file" -C /opt/
    rm -f "$tmp_file"

    # Create data directory
    mkdir -p "$DATA_DIR"

    # Set ownership
    chown -R "$MM_USER:$MM_USER" "$MM_DIR"

    log_info "Mattermost extracted to $MM_DIR"
}

# ============================================================================
# STEP 5: CONFIGURE MATTERMOST
# ============================================================================

configure_mattermost() {
    log_step "Configuring Mattermost..."

    local config_file="$MM_DIR/config/config.json"

    if [[ ! -f "$config_file" ]]; then
        log_error "Config file not found: $config_file"
        exit 1
    fi

    local dsn="postgres://${DB_USER}:${DB_PASS}@localhost:5432/${DB_NAME}?sslmode=disable&connect_timeout=10"

    # Use jq to update configuration
    local tmp_config
    tmp_config=$(mktemp)

    jq \
        --arg dsn "$dsn" \
        --arg siteurl "https://${DOMAIN}" \
        --arg datadir "$DATA_DIR" \
        '
        .SqlSettings.DriverName = "postgres" |
        .SqlSettings.DataSource = $dsn |
        .ServiceSettings.SiteURL = $siteurl |
        .ServiceSettings.ListenAddress = ":8065" |
        .FileSettings.Directory = $datadir
        ' "$config_file" > "$tmp_config"

    mv "$tmp_config" "$config_file"
    chown "$MM_USER:$MM_USER" "$config_file"
    chmod 600 "$config_file"

    log_info "Configuration updated: $config_file"
}

# ============================================================================
# STEP 6: CREATE SYSTEMD SERVICE
# ============================================================================

create_service() {
    log_step "Creating systemd service..."

    cat > /etc/systemd/system/mattermost.service <<EOF
[Unit]
Description=Mattermost Server
After=network.target postgresql.service

[Service]
Type=notify
User=$MM_USER
Group=$MM_USER
WorkingDirectory=$MM_DIR
ExecStart=$MM_DIR/bin/mattermost
Restart=always
RestartSec=10
LimitNOFILE=49152
TimeoutStartSec=3600

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable mattermost
    systemctl start mattermost

    sleep 3

    if systemctl is-active --quiet mattermost; then
        log_info "Mattermost service is running"
    else
        log_error "Mattermost failed to start — check: journalctl -u mattermost"
        systemctl status mattermost --no-pager || true
        exit 1
    fi
}

# ============================================================================
# STEP 7: NGINX REVERSE PROXY
# ============================================================================

configure_nginx() {
    if [[ "$NGINX_CONF" != true ]]; then
        log_info "Skipping nginx configuration (--no-nginx)"
        return 0
    fi

    log_step "Configuring nginx reverse proxy..."

    local nginx_config
    if [[ "$OS_FAMILY" == "debian" ]]; then
        nginx_config="/etc/nginx/sites-available/mattermost"
    else
        nginx_config="/etc/nginx/conf.d/mattermost.conf"
    fi

    cat > "$nginx_config" <<'NGINXEOF'
upstream mattermost_backend {
    server localhost:8065;
    keepalive 32;
}

server {
    listen 80;
    server_name DOMAIN_PLACEHOLDER;

    client_max_body_size 100M;

    location ~ /api/v[0-9]+/(users/)?websocket$ {
        proxy_pass http://mattermost_backend;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Frame-Options SAMEORIGIN;
        proxy_buffers 256 16k;
        proxy_buffer_size 16k;
        proxy_read_timeout 600s;
    }

    location / {
        proxy_pass http://mattermost_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Frame-Options SAMEORIGIN;
        proxy_buffers 256 16k;
        proxy_buffer_size 16k;
    }
}
NGINXEOF

    # Replace domain placeholder
    sed -i "s/DOMAIN_PLACEHOLDER/$DOMAIN/" "$nginx_config"

    # Enable site on Debian-based systems
    if [[ "$OS_FAMILY" == "debian" ]]; then
        mkdir -p /etc/nginx/sites-enabled
        ln -sf "$nginx_config" /etc/nginx/sites-enabled/mattermost
    fi

    # Test and reload nginx
    if nginx -t 2>/dev/null; then
        systemctl enable nginx
        systemctl reload nginx
        log_info "Nginx configured and reloaded"
    else
        log_error "Nginx configuration test failed"
        nginx -t
        exit 1
    fi
}

# ============================================================================
# STEP 8: SUMMARY
# ============================================================================

print_summary() {
    echo ""
    echo "============================================"
    echo "  Mattermost Installation Complete"
    echo "============================================"
    echo ""
    log_info "Database credentials:"
    echo "  User:     $DB_USER"
    echo "  Password: $DB_PASS"
    echo "  Database: $DB_NAME"
    echo ""
    log_info "Mattermost:"
    echo "  URL:      https://$DOMAIN"
    echo "  Service:  mattermost.service"
    echo "  Config:   $MM_DIR/config/config.json"
    echo "  Data:     $DATA_DIR"
    echo ""
    log_info "Next steps:"
    echo "  1. Set up TLS:    sudo certbot --nginx -d $DOMAIN"
    echo "  2. Visit https://$DOMAIN to create the admin account"
    echo "  3. View logs:     sudo journalctl -u mattermost -f"
    echo ""
}

# ============================================================================
# MAIN
# ============================================================================

main() {
    parse_args "$@"

    echo ""
    echo "============================================"
    echo "  Mattermost Install Script v${VERSION}"
    echo "  https://mylinux.work"
    echo "============================================"
    echo ""

    check_root
    detect_os
    install_dependencies
    configure_database
    create_system_user
    download_mattermost
    configure_mattermost
    create_service
    configure_nginx
    print_summary
}

main "$@"
