#!/usr/bin/env bash

#########################################################################################
#### deploy-freshrss.sh — Deploy FreshRSS with Docker Compose + Nginx reverse proxy  ####
#### Checks for existing configs, never overwrites. Safe to run on existing setups.  ####
####                                                                                 ####
#### Author: Phil Connor                                                             ####
#### Contact: contact@mylinux.work                                                   ####
#### License: MIT                                                                    ####
#### Version 1.00                                                                    ####
####                                                                                 ####
#### Usage:                                                                          ####
####   sudo ./deploy-freshrss.sh --domain rss.example.com                            ####
####   sudo ./deploy-freshrss.sh --domain rss.example.com --port 8081                ####
####   sudo ./deploy-freshrss.sh --dry-run --domain rss.example.com                  ####
####   sudo ./deploy-freshrss.sh --remove                                            ####
####                                                                                 ####
#### See --help for all options.                                                     ####
#########################################################################################

set -euo pipefail

DOMAIN=""
PORT="8080"
INSTALL_DIR="/opt/freshrss"
DB_PASSWORD=""
TZ="UTC"
CRON_MIN="*/15"
DRY_RUN=false
REMOVE=false
SKIP_NGINX=false
SKIP_SSL=false

# Colors
if [[ -t 1 ]]; then
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[0;33m'
    BOLD='\033[1m'
    RESET='\033[0m'
else
    RED="" GREEN="" YELLOW="" BOLD="" RESET=""
fi

log()  { echo -e "${GREEN}[OK]${RESET}    $*"; }
warn() { echo -e "${YELLOW}[WARN]${RESET}  $*"; }
err()  { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
info() { echo -e "${BOLD}[INFO]${RESET}  $*"; }

usage() {
    cat <<EOF
Usage: $(basename "$0") [OPTIONS]

Deploy FreshRSS with Docker Compose, PostgreSQL, and Nginx reverse proxy.

Installs:
  1. Docker Compose stack (FreshRSS + PostgreSQL) in /opt/freshrss/
  2. Nginx reverse proxy config in /etc/nginx/conf.d/
  3. Let's Encrypt SSL certificate (optional)

Options:
  --domain DOMAIN        Domain/subdomain for FreshRSS (required for install)
  --port PORT            Local port for FreshRSS container (default: 8080)
  --install-dir PATH     Installation directory (default: /opt/freshrss)
  --db-password PASS     PostgreSQL password (default: auto-generated)
  --timezone TZ          Timezone (default: UTC)
  --cron-min PATTERN     Feed update schedule (default: */15)
  --skip-nginx           Skip Nginx config (manual reverse proxy)
  --skip-ssl             Skip Let's Encrypt certificate
  --dry-run              Show what would be done without making changes
  --remove               Remove FreshRSS deployment
  -h, --help             Show this help

Examples:
  $(basename "$0") --domain rss.example.com
  $(basename "$0") --domain rss.example.com --port 8081 --timezone America/Chicago
  $(basename "$0") --domain rss.example.com --skip-ssl
  $(basename "$0") --dry-run --domain rss.example.com
  $(basename "$0") --remove
EOF
}

while [[ $# -gt 0 ]]; do
    case "$1" in
        --domain)       DOMAIN="$2"; shift ;;
        --port)         PORT="$2"; shift ;;
        --install-dir)  INSTALL_DIR="$2"; shift ;;
        --db-password)  DB_PASSWORD="$2"; shift ;;
        --timezone)     TZ="$2"; shift ;;
        --cron-min)     CRON_MIN="$2"; shift ;;
        --skip-nginx)   SKIP_NGINX=true ;;
        --skip-ssl)     SKIP_SSL=true ;;
        --dry-run)      DRY_RUN=true ;;
        --remove)       REMOVE=true ;;
        -h|--help)      usage; exit 0 ;;
        *)              err "Unknown option: $1"; usage; exit 1 ;;
    esac
    shift
done

if [[ $EUID -ne 0 ]]; then
    err "Must run as root (sudo)"
    exit 1
fi

# -- Remove mode --

if [[ "$REMOVE" == "true" ]]; then
    info "Removing FreshRSS deployment..."
    echo ""

    if [[ -f "${INSTALL_DIR}/docker-compose.yml" ]]; then
        if [[ "$DRY_RUN" == "true" ]]; then
            info "Would run: docker compose down in ${INSTALL_DIR}"
        else
            cd "$INSTALL_DIR"
            docker compose down 2>/dev/null || true
            log "Stopped FreshRSS containers"
        fi
    fi

    # Remove nginx config
    for f in /etc/nginx/conf.d/freshrss.conf /etc/nginx/sites-enabled/freshrss.conf /etc/nginx/sites-available/freshrss.conf; do
        if [[ -f "$f" ]]; then
            if [[ "$DRY_RUN" == "true" ]]; then
                info "Would remove: $f"
            else
                rm -f "$f"
                log "Removed $f"
            fi
        fi
    done

    if [[ "$DRY_RUN" != "true" ]] && command -v nginx &>/dev/null; then
        nginx -t 2>/dev/null && systemctl reload nginx 2>/dev/null && log "Reloaded Nginx"
    fi

    echo ""
    if [[ "$DRY_RUN" != "true" ]]; then
        log "Containers stopped and Nginx config removed."
        info "Data preserved at ${INSTALL_DIR}/ - remove manually if desired:"
        echo "  rm -rf ${INSTALL_DIR}"
    fi
    exit 0
fi

# -- Validation --

if [[ -z "$DOMAIN" ]]; then
    err "Domain is required: --domain rss.example.com"
    exit 1
fi

if ! command -v docker &>/dev/null; then
    err "Docker is not installed. Install Docker first."
    exit 1
fi

if ! docker compose version &>/dev/null 2>&1; then
    err "Docker Compose v2 is not available. Install docker-compose-plugin."
    exit 1
fi

# Generate DB password if not provided
if [[ -z "$DB_PASSWORD" ]]; then
    DB_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 24)
fi

# -- Install mode --

info "Deploying FreshRSS..."
echo ""
info "Domain:      ${DOMAIN}"
info "Port:        ${PORT}"
info "Install dir: ${INSTALL_DIR}"
info "Timezone:    ${TZ}"
info "Feed cron:   ${CRON_MIN}"
echo ""

# 1. Create directory
if [[ -d "$INSTALL_DIR" ]]; then
    info "Directory ${INSTALL_DIR} already exists"
else
    if [[ "$DRY_RUN" == "true" ]]; then
        info "Would create: ${INSTALL_DIR}"
    else
        mkdir -p "$INSTALL_DIR"
        log "Created ${INSTALL_DIR}"
    fi
fi

# 2. Docker Compose file
COMPOSE_FILE="${INSTALL_DIR}/docker-compose.yml"

if [[ -f "$COMPOSE_FILE" ]]; then
    info "docker-compose.yml already exists - skipping (delete to recreate)"
else
    if [[ "$DRY_RUN" == "true" ]]; then
        info "Would create: ${COMPOSE_FILE}"
    else
        cat > "$COMPOSE_FILE" <<YAML
services:
  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    ports:
      - "${PORT}:80"
    volumes:
      - ./data:/var/www/FreshRSS/data
      - ./extensions:/var/www/FreshRSS/extensions
    environment:
      - TZ=${TZ}
      - CRON_MIN=${CRON_MIN}
    depends_on:
      freshrss-db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:80"]
      interval: 30s
      timeout: 10s
      retries: 3

  freshrss-db:
    image: postgres:16-alpine
    container_name: freshrss-db
    restart: unless-stopped
    volumes:
      - ./postgres-data:/var/lib/postgresql/data
    environment:
      - POSTGRES_DB=freshrss
      - POSTGRES_USER=freshrss
      - POSTGRES_PASSWORD=${DB_PASSWORD}
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U freshrss"]
      interval: 10s
      timeout: 5s
      retries: 5
YAML
        log "Created ${COMPOSE_FILE}"
    fi
fi

# 3. Start containers
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^freshrss$'; then
    info "FreshRSS container is already running"
else
    if [[ "$DRY_RUN" == "true" ]]; then
        info "Would run: docker compose up -d"
    else
        cd "$INSTALL_DIR"
        docker compose up -d
        log "Started FreshRSS containers"
    fi
fi

# 4. Nginx reverse proxy
if [[ "$SKIP_NGINX" == "true" ]]; then
    info "Skipping Nginx config (--skip-nginx)"
elif ! command -v nginx &>/dev/null; then
    warn "Nginx not installed - skipping reverse proxy config"
    SKIP_NGINX=true
else
    NGINX_CONF=""
    # Detect config directory style
    if [[ -d /etc/nginx/conf.d ]]; then
        NGINX_CONF="/etc/nginx/conf.d/freshrss.conf"
    elif [[ -d /etc/nginx/sites-available ]]; then
        NGINX_CONF="/etc/nginx/sites-available/freshrss.conf"
    else
        warn "Could not detect Nginx config directory - skipping"
        SKIP_NGINX=true
    fi

    if [[ "$SKIP_NGINX" != "true" && -n "$NGINX_CONF" ]]; then
        if [[ -f "$NGINX_CONF" ]]; then
            info "Nginx config already exists at ${NGINX_CONF} - skipping"
        else
            if [[ "$DRY_RUN" == "true" ]]; then
                info "Would create: ${NGINX_CONF}"
            else
                if [[ "$SKIP_SSL" == "true" ]]; then
                    # HTTP only
                    cat > "$NGINX_CONF" <<NGINX
server {
    listen 80;
    server_name ${DOMAIN};

    location / {
        proxy_pass http://127.0.0.1:${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;
    }
}
NGINX
                else
                    # HTTPS with placeholder (certbot will fill in)
                    cat > "$NGINX_CONF" <<NGINX
server {
    listen 80;
    server_name ${DOMAIN};
    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_pass http://127.0.0.1:${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;
    }
}
NGINX
                fi

                log "Created ${NGINX_CONF}"

                # Symlink if sites-available style
                if [[ "$NGINX_CONF" == *sites-available* ]]; then
                    ln -sf "$NGINX_CONF" /etc/nginx/sites-enabled/freshrss.conf
                    log "Symlinked to sites-enabled"
                fi
            fi
        fi
    fi
fi

# 5. SSL certificate
if [[ "$SKIP_SSL" != "true" && "$SKIP_NGINX" != "true" ]]; then
    if [[ -d "/etc/letsencrypt/live/${DOMAIN}" ]]; then
        info "SSL certificate already exists for ${DOMAIN}"
    elif command -v certbot &>/dev/null; then
        if [[ "$DRY_RUN" == "true" ]]; then
            info "Would run: certbot certonly --nginx -d ${DOMAIN}"
        else
            certbot certonly --nginx -d "$DOMAIN" --non-interactive --agree-tos --register-unsafely-without-email || {
                warn "Certbot failed - configure SSL manually"
                warn "Run: certbot certonly --nginx -d ${DOMAIN}"
            }
        fi
    else
        warn "certbot not installed - configure SSL manually"
    fi
fi

# 6. Reload Nginx
if [[ "$SKIP_NGINX" != "true" && "$DRY_RUN" != "true" ]]; then
    if nginx -t 2>/dev/null; then
        systemctl reload nginx
        log "Reloaded Nginx"
    else
        warn "Nginx config test failed - check config manually"
    fi
fi

# -- Summary --

echo ""
echo -e "${BOLD}Deployment summary:${RESET}"
echo "  Docker Compose:  ${INSTALL_DIR}/docker-compose.yml"
echo "  FreshRSS:        http://127.0.0.1:${PORT}"
if [[ "$SKIP_NGINX" != "true" ]]; then
    if [[ "$SKIP_SSL" == "true" ]]; then
        echo "  Public URL:      http://${DOMAIN}"
    else
        echo "  Public URL:      https://${DOMAIN}"
    fi
    echo "  Nginx config:    ${NGINX_CONF:-/etc/nginx/conf.d/freshrss.conf}"
fi
echo "  Database:        PostgreSQL (freshrss-db container)"
echo "  Feed updates:    Every ${CRON_MIN} minutes"
echo "  Data directory:  ${INSTALL_DIR}/data/"
echo ""
echo -e "${BOLD}Next steps:${RESET}"
if [[ "$SKIP_SSL" == "true" ]]; then
    echo "  1. Open http://${DOMAIN} and complete the setup wizard"
else
    echo "  1. Open https://${DOMAIN} and complete the setup wizard"
fi
echo "  2. Database config in wizard:"
echo "       Type:     PostgreSQL"
echo "       Host:     freshrss-db"
echo "       Database: freshrss"
echo "       User:     freshrss"
echo "       Password: (saved in ${INSTALL_DIR}/docker-compose.yml)"
echo "  3. Create your admin account"
echo "  4. Add your first feed: https://mylinux.work/index.xml"
echo ""
info "Remove with: $(basename "$0") --remove"
