#!/bin/bash
# /usr/local/bin/gitpi-deploy
# V7 - Gold Master: Optimized, Clean, Robust

# Exit on critical errors
set -e

export CI=true

REPO_NAME="$1"
SOURCE_DIR="$2"
CONFIG_FILE="$SOURCE_DIR/.gitpideploy"

# --- DEFAULTS ---
MODE="app" 
DEST_DIR="/srv/gitpi/$REPO_NAME"
START_CMD=""
DOMAIN=""
PORT=""
EMAIL="amykrippner@outlook.de"

echo "DEPLOY.."

# --- LOGGING ---
log() { echo -e "🔹 $1"; }
success() { echo -e "✅ $1"; }
warn() { echo -e "⚠️  $1"; }
err() { echo -e "❌ $1"; exit 1; }

# --- HELPER: SSL CHECK ---
check_ssl_expiry() {
    local dom=$1
    local cert="/etc/letsencrypt/live/$dom/fullchain.pem"
    if [ -f "$cert" ]; then
        # Prüft ob Zertifikat noch > 14 Tage (1209600 sek) gültig ist
        if openssl x509 -checkend 1209600 -noout -in "$cert"; then
            return 0 
        fi
    fi
    return 1 
}

# --- 1. ROBUST CONFIG PARSER ---
parse_config() {
    if [ ! -f "$CONFIG_FILE" ]; then return; fi
    
    log "Reading configuration..."
    local current_section="NONE"
    
    # Vorbereitung: Env-File leeren/erstellen
    mkdir -p "$DEST_DIR"
    echo "# Auto-generated by gitpi-deploy" > "$DEST_DIR/.env.deploy"

    while IFS= read -r line || [[ -n "$line" ]]; do
        # Leerzeilen und Kommentare ignorieren
        [[ -z "$line" ]] && continue
        [[ "$line" =~ ^#.*$ ]] && continue
        
        # Sektions-Erkennung [SECTION]
        if [[ "$line" =~ ^\[(.*)\]$ ]]; then
            current_section="${BASH_REMATCH[1]}"
            continue
        fi

        # Key=Value Parsing
        if [[ "$line" =~ ^([^=]+)=(.*)$ ]]; then
            local key=$(echo "${BASH_REMATCH[1]}" | xargs)
            
            # NEU: Wir entfernen Anführungszeichen beim Einlesen der Werte!
            local val=$(echo "${BASH_REMATCH[2]}" | tr -d \'\" | xargs)

            if [[ "$current_section" == "GITPI" ]]; then
                # Export für dieses Bash-Script
                export "$key"="$val"
            elif [[ "$current_section" == "ENV" ]]; then
                # Schreiben in .env Datei für die App
                echo "$key=$val" >> "$DEST_DIR/.env.deploy"
            fi
        fi
    done < "$CONFIG_FILE"
}

# --- 2. NGINX GENERATOR ---
update_nginx() {
    local conf_path="/etc/nginx/sites-available/$DOMAIN.conf"
    local enabled_path="/etc/nginx/sites-enabled/$DOMAIN.conf"
    local proxy_block=""

    log "Configuring Nginx for $DOMAIN..."

    # Entscheide Inhalt basierend auf Modus
    if [ "$MODE" == "static" ]; then
        proxy_block="
        root $DEST_DIR;
        index index.html index.htm;
        try_files \$uri \$uri/ /index.html;"
    else
        # App Mode (Reverse Proxy)
        proxy_block="
        proxy_pass http://127.0.0.1:$PORT;
        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;"
    fi

    # Schreibe Config
    cat <<EOF > "$conf_path"
server {
    listen 80;
    server_name $DOMAIN;
    location /.well-known/acme-challenge { allow all; root /var/www/html; }
    location / { return 301 https://\$host\$request_uri; }
}
server {
    listen 443 ssl http2;
    server_name $DOMAIN;

    ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;

    location / {
        $proxy_block
    }
}
EOF

    ln -sf "$conf_path" "$enabled_path"
    nginx -t && systemctl reload nginx || warn "Nginx config failed verification!"
    success "Nginx updated."
}

# ==========================================
# MAIN EXECUTION FLOW
# ==========================================

if [ ! -f "$CONFIG_FILE" ]; then
    warn "No .gitpideploy found. Skipping deployment logic."
    exit 0
fi

# 1. Config lesen (um DEST_DIR und MODE zu kennen)
# Wave 1 safety: parse DEST_DIR as data, never execute project config text.
DEST_DIR_LINE=$(grep "DEST_DIR=" "$CONFIG_FILE" | head -n 1 || true)
if [ -n "$DEST_DIR_LINE" ]; then
    DEST_DIR_VALUE="${DEST_DIR_LINE#*=}"
    DEST_DIR_VALUE="${DEST_DIR_VALUE%\"}"
    DEST_DIR_VALUE="${DEST_DIR_VALUE#\"}"
    DEST_DIR_VALUE="${DEST_DIR_VALUE%\'}"
    DEST_DIR_VALUE="${DEST_DIR_VALUE#\'}"
    if [ -n "$DEST_DIR_VALUE" ]; then
        DEST_DIR="$DEST_DIR_VALUE"
    fi
fi
mkdir -p "$DEST_DIR"
parse_config

echo "🚀 STARTE DEPLOYMENT: $REPO_NAME ($MODE)"

# 2. SSL & NGINX (Nur wenn Domain gesetzt)
if [ -n "$DOMAIN" ]; then
    if ! check_ssl_expiry "$DOMAIN"; then
        log "Requesting SSL Cert for $DOMAIN..."
        certbot certonly --dns-cloudflare --dns-cloudflare-credentials '/etc/letsencrypt/cloudflare.ini' \
            -d "$DOMAIN" --agree-tos --email "$EMAIL" --non-interactive --expand
    else
        success "SSL Cert valid."
    fi
    update_nginx
fi

# 3. MODUS-SPEZIFISCHE LOGIK
case "$MODE" in
    # --- SYNC MODE (Dotfiles etc) ---
    sync)
        if [ -z "$TARGET_DIR" ]; then err "TARGET_DIR missing in config!"; fi
        
        # Tilde Expansion für Zielpfad
        REAL_TARGET="${TARGET_DIR/#\~//home/$OWNER_USER}"
        log "Syncing to $REAL_TARGET (Owner: $OWNER_USER)..."
        
        mkdir -p "$REAL_TARGET"
        rsync -a --delete --exclude '.git' --exclude '.gitpideploy' --exclude '.env' "$SOURCE_DIR/" "$REAL_TARGET/"
        chown -R "$OWNER_USER:$OWNER_USER" "$REAL_TARGET"

        if [ -n "$POST_DEPLOY_CMD" ]; then
            log "Running Post-Deploy Command..."
            if [ "$OWNER_USER" == "root" ]; then
                bash -lc "$POST_DEPLOY_CMD"
            else
                su -c "$POST_DEPLOY_CMD" "$OWNER_USER"
            fi
        fi
        success "Sync complete."
        ;;
    # --- BINARY MODE (CLI Tools / Binaries) ---
    bin)
        local PKG_DIR="$HOME/.local/share/gitpi/packages/$REPO_NAME"
        local BIN_DIR="$HOME/.local/share/gitpi/bin"
        
        log "📦 GitPi-Packager: Installing $REPO_NAME..."
        mkdir -p "$PKG_DIR" "$BIN_DIR"

        # Sync Code (Sicherer Hafen für den Quellcode)
        rsync -a --delete --exclude '.git' "$SOURCE_DIR/" "$PKG_DIR/"
        cd "$PKG_DIR"

        # --- AUTOMATISCHE ERKENNUNG & INSTALLATION ---
        if [ -f "package.json" ]; then
            log "🛠️  Detected Node.js. Using npm to resolve deps..."
            npm install --production --no-audit --quiet
            
            # Verlinke Binaries aus package.json
            node -e "const j=require('./package.json').bin; const b=typeof j==='string'?{['$REPO_NAME']:j}:(j||{}); Object.keys(b).forEach(k=>console.log(k+':'+b[k]))" | while read -r entry; do
                local name="${entry%%:*}"
                local path="${entry#*:}"
                ln -sf "$PKG_DIR/$path" "$BIN_DIR/$name"
                chmod +x "$PKG_DIR/$path"
                success "Linked Node-Bin: $name"
            done

        elif [ -f "setup.py" ] || [ -f "pyproject.toml" ]; then
            log "🐍 Detected Python. Creating/Updating Editable Install..."
            # Wir nutzen 'pip install -e' in den User-Space, 
            # aber wir erzwingen den Bin-Path in unseren GitPi-Ordner
            pip install --user --no-cache-dir --break-system-packages -e . --install-option="--install-scripts=$BIN_DIR" 2>/dev/null || \
            pip install --user -e . # Fallback für neuere Pip-Versionen
            
            # Da Pip oft stur nach ~/.local/bin linkt, korrigieren wir das kurz:
            # (Optional: Wir könnten hier auch manuell aus der pyproject.toml lesen)
            success "Python package linked via Pip."
        fi
        
        success "Deployment of $REPO_NAME complete."
        ;;

    # --- STATIC WEB MODE ---
    static)
        log "Deploying Static Site to $DEST_DIR..."
        rsync -a --delete --exclude '.git' --exclude '.gitpideploy' "$SOURCE_DIR/" "$DEST_DIR/"
        
        # Permissions für Webserver
        chown -R www-data:www-data "$DEST_DIR"
        chmod -R 755 "$DEST_DIR"
        success "Static site deployed."
        ;;

    # --- APP MODE (NodeJS/Python) ---
    app)
        log "Deploying App to $DEST_DIR..."
        
        # File Sync
        rsync -a --delete --exclude '.git' --exclude 'node_modules' --exclude '.gitpideploy' "$SOURCE_DIR/" "$DEST_DIR/"
        
        # Check if the .env was uploaded to the build dir via 'gitpi env'
        if [ -f "$SOURCE_DIR/.env" ]; then
            log "🔑 Manual .env detected. Syncing to production..."
            cp "$SOURCE_DIR/.env" "$DEST_DIR/.env"
            # Set permissions so DynamicUser can read it, but others can't
            chmod 644 "$DEST_DIR/.env" 
        fi

        cd "$DEST_DIR"

        # 3. INSTALLATION LOGIC
        # Wir setzen HOME temporär um
        export HOME="/tmp/gitpi-build-$REPO_NAME"
        mkdir -p "$HOME"

        # Dependencies
        if [ -n "$INSTALL_CMD" ]; then
            log "🛠️  Running custom INSTALL_CMD: $INSTALL_CMD"
            bash -lc "$INSTALL_CMD"
        elif [ -f "package.json" ]; then
            log "📦 Node.js detected. Running auto-install..."
            if [ -f "pnpm-lock.yaml" ] && command -v pnpm &> /dev/null; then
                pnpm install --prod --frozen-lockfile
            else
                npm ci --production --no-audit
            fi
        fi
        rm -rf "$HOME"

        # Start Command Fallback
        if [ -z "$START_CMD" ] && [ -f "package.json" ]; then
            START_CMD="npm start"
        fi
        
        # Node Binary Finder
        NODE_BIN=$(which node)
        if [ -z "$NODE_BIN" ]; then err "NodeJS not found on system!"; fi

        # Systemd Config
        SERVICE_NAME="gitpi-$REPO_NAME"
        SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service"
        
        log "Updating Systemd Service: $SERVICE_NAME"
        
        cat <<EOF > "$SERVICE_FILE"
[Unit]
Description=GitPi: $REPO_NAME $NODE_BIN $START_CMD
After=network.target

[Service]
Type=simple
DynamicUser=yes
WorkingDirectory=$DEST_DIR
ExecStart=$START_CMD
Restart=always
RestartSec=10

# Environment
EnvironmentFile=-$DEST_DIR/.env.deploy
EnvironmentFile=-$DEST_DIR/.env
Environment=PORT=$PORT
Environment=DOMAIN=$DOMAIN
Environment=NODE_ENV=production

# Storage Mapping
StateDirectory=gitpi-$REPO_NAME
CacheDirectory=gitpi-$REPO_NAME
LogsDirectory=gitpi-$REPO_NAME

# Writable Paths for Node
Environment=HOME=/var/lib/gitpi-$REPO_NAME
Environment=XDG_CACHE_HOME=/var/cache/gitpi-$REPO_NAME
Environment=npm_config_cache=/var/cache/gitpi-$REPO_NAME/npm
Environment=DATA_PATH=/var/lib/gitpi-$REPO_NAME

# Hardening
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target
EOF

        systemctl daemon-reload
        systemctl enable "$SERVICE_NAME"
        systemctl restart "$SERVICE_NAME"
        
        success "App Service deployed & restarted on Port $PORT."
        ;;

    *)
        err "Unknown MODE: $MODE"
        ;;
esac
