#!/bin/bash
# ==========================================
# AEA SERVER MODULE: MATRIX SYNAPSE
# VERSION: 1.01 (Dynamic CDN Mirror Integration)
# ==========================================
AEA_VERSION="1.01"

INFO_FILE="/etc/aea_matrix.info"
DATA_DIR="/opt/aea_matrix_synapse"
# Используем 6168, чтобы избежать конфликтов со старым Conduit (6167)
MATRIX_PORT=6168
LOG_FILE="/var/log/aea_matrix_synapse_install.log"

AEA_MIRROR_URL="{{AEA_MIRROR_URL}}"
if [[ "$AEA_MIRROR_URL" == "{{"* ]]; then
    AEA_MIRROR_URL="https://download.aea-aiserver.ru/mirror"
fi

if [ "$1" == "--version" ] || [ "$1" == "-v" ]; then
    echo "$AEA_VERSION"
    exit 0
fi

if [ "$1" == "--info" ]; then
    if [ -f "$INFO_FILE" ]; then base64 -d "$INFO_FILE"; else echo '{"status": "not_installed"}'; fi
    exit 0
fi

if [ "$1" == "--check" ]; then
    OS_ID=$(grep -E '^(ID)=' /etc/os-release | cut -d '=' -f 2 | tr -d '"')
    RAM_TOTAL=$(free -m | awk '/^Mem:/{print $2}')
    ss -tuln | grep -q ":80 " && PORT_80="busy" || PORT_80="free"
    ss -tuln | grep -q ":443 " && PORT_443="busy" || PORT_443="free"
    ss -tuln | grep -q ":$MATRIX_PORT " && PORT_MATRIX="busy" || PORT_MATRIX="free"
    command -v nginx >/dev/null 2>&1 && HAS_NGINX="yes" || HAS_NGINX="no"
    command -v docker >/dev/null 2>&1 && HAS_DOCKER="yes" || HAS_DOCKER="no"
    cat <<EOF
{
  "os": "$OS_ID",
  "ram_mb": $RAM_TOTAL,
  "ports": {"80": "$PORT_80", "443": "$PORT_443", "$MATRIX_PORT": "$PORT_MATRIX"},
  "software": {"nginx": "$HAS_NGINX", "docker": "$HAS_DOCKER"},
  "ready_standalone": $(if [ "$PORT_MATRIX" == "free" ] && [ "$PORT_80" == "free" -o "$HAS_NGINX" == "yes" ]; then echo "true"; else echo "false"; fi),
  "ready_master": $(if [ "$PORT_80" == "free" -o "$HAS_NGINX" == "yes" ]; then echo "true"; else echo "false"; fi),
  "ready_node": $(if [ "$PORT_MATRIX" == "free" ]; then echo "true"; else echo "false"; fi)
}
EOF
    exit 0
fi

if [ "$1" == "--remove" ]; then
    echo "[AEA] Removing Synapse module components..."
    if command -v docker >/dev/null 2>&1; then
        docker stop aea_matrix_synapse >/dev/null 2>&1
        docker rm aea_matrix_synapse >/dev/null 2>&1
    fi
    rm -rf "$DATA_DIR" "$INFO_FILE" "$LOG_FILE"
    if [ -f "/etc/nginx/sites-enabled/aea_matrix" ]; then
        rm -f /etc/nginx/sites-enabled/aea_matrix /etc/nginx/sites-available/aea_matrix
        systemctl reload nginx >/dev/null 2>&1
    fi
    exit 0
fi

MODE="${1:-"{{MATRIX_MODE}}"}"
DOMAIN="${2:-"{{MATRIX_DOMAIN}}"}"
EMAIL="${3:-"{{MATRIX_EMAIL}}"}"
NODE_IP="${4:-"{{MATRIX_NODE_IP}}"}"

ADMIN_USER="{{MATRIX_ADMIN_USER}}"
ADMIN_PASS="{{MATRIX_ADMIN_PASS}}"

if [ "$MODE" == "{{MATRIX_MODE}}" ] || [ -z "$MODE" ]; then MODE="--install-standalone"; fi
if [ "$EMAIL" == "{{MATRIX_EMAIL}}" ]; then EMAIL=""; fi

if [[ "$ADMIN_USER" == "{{"* ]]; then ADMIN_USER=""; ADMIN_PASS=""; fi

if [[ "$MODE" == --install* ]]; then
    > "$LOG_FILE"
    echo "=== AEA SYNAPSE INSTALLATION LOG START: $(date) ===" >> "$LOG_FILE"
fi

log_echo() { echo "$1"; echo "[$(date '+%H:%M:%S')] $1" >> "$LOG_FILE"; }

if [[ "$DOMAIN" == "{{"* ]] || [ -z "$DOMAIN" ]; then
    log_echo "[AEA] CRITICAL ERROR: Domain name is missing!"
    exit 1
fi

setup_docker() {
    export DEBIAN_FRONTEND=noninteractive
    # 1. Обновляем репозитории и ставим sqlite3, curl, wget
    apt-get update -yq >> "$LOG_FILE" 2>&1
    apt-get install -yq sqlite3 curl wget >> "$LOG_FILE" 2>&1

    # 2. Ставим Docker, только если его еще нет
    if ! command -v docker >/dev/null 2>&1; then
        apt-get install -yq docker.io >> "$LOG_FILE" 2>&1
        systemctl enable --now docker >> "$LOG_FILE" 2>&1
    fi
}

setup_web() {
    if ! command -v nginx >/dev/null 2>&1; then
        export DEBIAN_FRONTEND=noninteractive
        apt-get update -yq >> "$LOG_FILE" 2>&1
        apt-get install -yq nginx certbot python3-certbot-nginx >> "$LOG_FILE" 2>&1
    fi
    rm -f /etc/nginx/sites-enabled/default >> "$LOG_FILE" 2>&1
    if command -v ufw >/dev/null 2>&1; then
        ufw allow 'Nginx Full' >> "$LOG_FILE" 2>&1
        ufw allow 80/tcp >> "$LOG_FILE" 2>&1
        ufw allow 443/tcp >> "$LOG_FILE" 2>&1
        ufw reload >> "$LOG_FILE" 2>&1
    fi
}

deploy_matrix() {
    mkdir -p "$DATA_DIR/data" >> "$LOG_FILE" 2>&1

    # ============================================================
    # УМНАЯ ЗАГРУЗКА ИЗ ДИНАМИЧЕСКОГО ЗЕРКАЛА
    # ============================================================
    TAR_FILE="matrix_synapse.tar.gz"
    log_echo "[AEA] Attempting to fetch Matrix Synapse from AEA Mirror: $AEA_MIRROR_URL..."
    
    if wget -q --spider "$AEA_MIRROR_URL/$TAR_FILE"; then
        log_echo "[AEA] Mirror is online. Downloading archive..."
        wget -qO "/tmp/$TAR_FILE" "$AEA_MIRROR_URL/$TAR_FILE"
        log_echo "[AEA] Pre-loading Docker image to bypass blocks..."
        docker load -i "/tmp/$TAR_FILE" >> "$LOG_FILE" 2>&1
        rm -f "/tmp/$TAR_FILE"
    else
        log_echo "[AEA] Mirror unreachable. Falling back to public registry..."
        docker pull matrixdotorg/synapse:latest >> "$LOG_FILE" 2>&1
    fi
    # ============================================================

    log_echo "[AEA] Generating baseline Synapse configuration..."
    # Synapse требует генерации базового конфига перед первым запуском
    docker run --rm -v "$DATA_DIR/data:/data" \
      -e SYNAPSE_SERVER_NAME="${DOMAIN}" \
      -e SYNAPSE_REPORT_STATS=no \
      matrixdotorg/synapse:latest generate >> "$LOG_FILE" 2>&1

    log_echo "[AEA] Starting Synapse container..."
    # Внутренний порт Synapse всегда 8008, мы мапим его на наш 6168
    docker run -d --name aea_matrix_synapse --restart unless-stopped \
      -p $MATRIX_PORT:8008 \
      -v "$DATA_DIR/data:/data" \
      matrixdotorg/synapse:latest >> "$LOG_FILE" 2>&1
}

deploy_proxy() {
    LOCAL_TARGET=${1:-"127.0.0.1"}

    generate_https_config() {
        cat > /etc/nginx/sites-available/aea_matrix << 'EOF_NGINX'
server {
    listen 80;
    server_name SERVER_DOMAIN;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    server_name SERVER_DOMAIN;
    client_max_body_size 50M;

    ssl_certificate /etc/letsencrypt/live/SERVER_DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/SERVER_DOMAIN/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;

    location / {
        proxy_pass http://LOCAL_TARGET:MATRIX_PORT;
        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_http_version 1.1;
    }

    location /.well-known/matrix/server {
        default_type application/json;
        add_header Access-Control-Allow-Origin * always;
        return 200 '{"m.server": "SERVER_DOMAIN:443"}';
    }

    location /.well-known/matrix/client {
        default_type application/json;
        add_header Access-Control-Allow-Origin * always;
        return 200 '{"m.homeserver": {"base_url": "https://SERVER_DOMAIN"}}';
    }
}
EOF_NGINX

        sed -i "s|SERVER_DOMAIN|${DOMAIN}|g" /etc/nginx/sites-available/aea_matrix
        sed -i "s|LOCAL_TARGET|${LOCAL_TARGET}|g" /etc/nginx/sites-available/aea_matrix
        sed -i "s|MATRIX_PORT|${MATRIX_PORT}|g" /etc/nginx/sites-available/aea_matrix
    }

    log_echo "[AEA] Setting up temporary HTTP config for Certbot..." >> "$LOG_FILE"
    cat > /etc/nginx/sites-available/aea_matrix << EOF
server {
    listen 80;
    server_name ${DOMAIN};
    location / { proxy_pass http://${LOCAL_TARGET}:$MATRIX_PORT; }
}
EOF
    ln -sf /etc/nginx/sites-available/aea_matrix /etc/nginx/sites-enabled/
    systemctl restart nginx >> "$LOG_FILE" 2>&1

    if [ ! -f "/etc/letsencrypt/live/${DOMAIN}/fullchain.pem" ]; then
        log_echo "[AEA] Requesting SSL Certificate via certonly..." >> "$LOG_FILE"
        CERTBOT_EMAIL="--register-unsafely-without-email"
        if [ -n "$EMAIL" ]; then CERTBOT_EMAIL="-m $EMAIL"; fi
        certbot certonly --nginx -d "${DOMAIN}" --non-interactive --agree-tos $CERTBOT_EMAIL --keep-until-expiring >> "$LOG_FILE" 2>&1
    else
        log_echo "[AEA] SSL Certificate already exists on disk." >> "$LOG_FILE"
    fi

    log_echo "[AEA] Writing strict HTTPS config..." >> "$LOG_FILE"
    generate_https_config

    if nginx -t >> "$LOG_FILE" 2>&1; then
        systemctl restart nginx >> "$LOG_FILE" 2>&1
        log_echo "[AEA] Proxy deployment completed successfully."
    else
        log_echo "[AEA] CRITICAL ERROR: Nginx config test failed!" >> "$LOG_FILE"
    fi
}

setup_admin() {
    if [ -n "$ADMIN_USER" ] && [ -n "$ADMIN_PASS" ]; then
        log_echo "[AEA] Waiting for Synapse initialization (25s)..."
        sleep 25

        log_echo "[AEA] Registering Admin User via native CLI: $ADMIN_USER"
        # Synapse имеет родную утилиту для создания пользователей, не нужно трогать конфиги регистрации!
        docker exec aea_matrix_synapse register_new_matrix_user -u "$ADMIN_USER" -p "$ADMIN_PASS" -a -c /data/homeserver.yaml http://localhost:8008 >> "$LOG_FILE" 2>&1

        if [ $? -eq 0 ]; then
            echo "{\"user\":\"$ADMIN_USER\", \"pass\":\"$ADMIN_PASS\"}" > /opt/aea_matrix_synapse/.admin_creds
            chmod 600 /opt/aea_matrix_synapse/.admin_creds
            log_echo "[AEA] Admin successfully created!"
        else
            log_echo "[AEA] Failed to create admin user. Check logs."
        fi
    else
        log_echo "[AEA] Admin credentials not provided. Skipping admin creation."
    fi
}

case "$MODE" in
    --install-standalone) setup_docker; setup_web; deploy_matrix; deploy_proxy "127.0.0.1"; setup_admin; JSON_DATA="{\"status\": \"success\", \"mode\": \"standalone\", \"domain\": \"$DOMAIN\"}" ;;
    --install-master) setup_web; deploy_proxy "$NODE_IP"; JSON_DATA="{\"status\": \"success\", \"mode\": \"master\", \"domain\": \"$DOMAIN\", \"target_ip\": \"$NODE_IP\"}" ;;
    --install-node) setup_docker; deploy_matrix; setup_admin; JSON_DATA="{\"status\": \"success\", \"mode\": \"node\", \"domain\": \"$DOMAIN\", \"port\": $MATRIX_PORT}" ;;
esac

echo "$JSON_DATA" | base64 -w 0 > "$INFO_FILE"
chmod 600 "$INFO_FILE"

MODULE_PATH="/usr/local/bin/aea_matrix_synapse"
cat "$0" > "$MODULE_PATH"
chmod +x "$MODULE_PATH"

exit 0
