#!/usr/bin/env bash
# =============================================================================
# setup-almalinux9.sh — RecreaHUB API — AlmaLinux 9 / Rocky 9 / RHEL 9
# =============================================================================
# Uso:
#   sudo bash setup-almalinux9.sh [opções]
#
# Opções:
#   --dry-run    Exibe os comandos sem executar
#   --no-nginx   Pula instalação do Nginx / Certbot
#   --port N     Porta da aplicação Node (padrão: 3000)
# =============================================================================

set -euo pipefail

# ---------------------------------------------------------------------------
# Cores e helpers
# ---------------------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'

log()   { echo -e "${GREEN}[INFO]${RESET}  $*"; }
warn()  { echo -e "${YELLOW}[WARN]${RESET}  $*"; }
error() { echo -e "${RED}[ERROR]${RESET} $*" >&2; }
section() {
    echo ""
    echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
    echo -e "${CYAN}${BOLD}  $*${RESET}"
    echo -e "${CYAN}${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${RESET}"
}

# ---------------------------------------------------------------------------
# Flags
# ---------------------------------------------------------------------------
DRY_RUN=false
NO_NGINX=false
APP_PORT=3000

for arg in "$@"; do
    case "$arg" in
        --dry-run)  DRY_RUN=true ;;
        --no-nginx) NO_NGINX=true ;;
        --port)     shift; APP_PORT="${1:-3000}" ;;
        --port=*)   APP_PORT="${arg#*=}" ;;
    esac
done

run() {
    if [ "$DRY_RUN" = true ]; then
        echo -e "${YELLOW}[DRY-RUN]${RESET} $*"
    else
        eval "$@"
    fi
}

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

# ---------------------------------------------------------------------------
# 1. Verificar AlmaLinux 9
# ---------------------------------------------------------------------------
check_almalinux9() {
    section "1. Verificando sistema operacional"

    local os_id="" os_version=""

    if [ -f /etc/almalinux-release ]; then
        log "Arquivo /etc/almalinux-release encontrado."
        os_id="almalinux"
        os_version=$(grep -oP '\d+' /etc/almalinux-release | head -1)
    elif [ -f /etc/os-release ]; then
        os_id=$(grep -E '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"')
        os_version=$(grep -E '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"' | cut -d. -f1)
    else
        error "Arquivo /etc/os-release não encontrado. Sistema não identificado."
        exit 1
    fi

    log "Sistema detectado: ID=${os_id}, VERSION_ID_MAJOR=${os_version}"

    # Aceitar também Rocky Linux 9 e RHEL 9 (binariamente compatíveis)
    case "$os_id" in
        almalinux|rocky|rhel)
            if [ "$os_version" != "9" ]; then
                error "Este script requer AlmaLinux 9 / Rocky 9 / RHEL 9."
                error "Versão detectada: ${os_id} ${os_version}"
                error "Para CentOS 7, use: bash setup-centos7.sh"
                exit 1
            fi
            ;;
        *)
            error "Sistema não suportado: ${os_id} ${os_version}"
            error "Este script foi projetado para AlmaLinux 9, Rocky Linux 9 ou RHEL 9."
            exit 1
            ;;
    esac

    log "Sistema compatível: ${os_id} ${os_version} — OK"
}

# ---------------------------------------------------------------------------
# 2. Verificar root
# ---------------------------------------------------------------------------
check_root() {
    section "2. Verificando permissões"

    if [ "$(id -u)" -ne 0 ]; then
        error "Este script deve ser executado como root."
        error "Use: sudo bash $0 $*"
        exit 1
    fi
    log "Executando como root — OK"
}

# ---------------------------------------------------------------------------
# 3. Instalar pacotes base
# ---------------------------------------------------------------------------
install_base() {
    section "3. Instalando pacotes base"

    log "Atualizando sistema..."
    run "dnf update -y"

    log "Instalando utilitários essenciais..."
    run "dnf install -y curl wget git"

    log "Instalando EPEL release..."
    run "dnf install -y epel-release"

    log "Habilitando CodeReady Builder (CRB) — necessário para EPEL completo..."
    run "dnf config-manager --set-enabled crb"

    log "Atualizando lista de pacotes pós-CRB..."
    run "dnf makecache"

    log "Pacotes base instalados — OK"
}

# ---------------------------------------------------------------------------
# 4. Instalar Node.js 20 LTS
# ---------------------------------------------------------------------------
install_nodejs() {
    section "4. Instalando Node.js 20 LTS"

    if command -v node &>/dev/null; then
        local current_version
        current_version=$(node -v)
        warn "Node.js já está instalado: ${current_version}"
        warn "Se desejar reinstalar, remova primeiro com: dnf remove nodejs"
    else
        log "Adicionando repositório NodeSource para Node.js 20..."
        run "curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -"

        log "Instalando Node.js 20..."
        run "dnf install -y nodejs"
    fi

    log "Versões instaladas:"
    node -v || true
    npm -v  || true
    log "Node.js instalado — OK"
}

# ---------------------------------------------------------------------------
# 5. Instalar PM2
# ---------------------------------------------------------------------------
install_pm2() {
    section "5. Instalando PM2"

    if command -v pm2 &>/dev/null; then
        warn "PM2 já está instalado: $(pm2 -v)"
    else
        log "Instalando PM2 globalmente..."
        run "npm install -g pm2"
    fi

    log "PM2 instalado — OK"
}

# ---------------------------------------------------------------------------
# 6. Deploy da aplicação
# ---------------------------------------------------------------------------
deploy_app() {
    section "6. Deploy da aplicação"

    local app_dir="/opt/recreahub-api"
    local source_dir
    source_dir="$(dirname "$SCRIPT_DIR")"

    log "Criando diretório: ${app_dir}"
    run "mkdir -p ${app_dir}"

    log "Copiando arquivos da aplicação de ${source_dir} para ${app_dir}..."
    run "cp -r \"${source_dir}/.\" \"${app_dir}/\""

    log "Instalando dependências de produção..."
    run "cd ${app_dir} && npm install --omit=dev"

    # Criar usuário de sistema se não existir
    if ! id -u recreahub &>/dev/null; then
        log "Criando usuário de sistema 'recreahub'..."
        run "useradd -r -s /sbin/nologin recreahub"
    else
        warn "Usuário 'recreahub' já existe — pulando criação."
    fi

    log "Ajustando permissões..."
    run "chown -R recreahub:recreahub ${app_dir}"

    # Copiar .env.example para .env se .env não existir
    if [ ! -f "${app_dir}/.env" ]; then
        if [ -f "${app_dir}/.env.example" ]; then
            log "Copiando .env.example para .env..."
            run "cp ${app_dir}/.env.example ${app_dir}/.env"
            warn "IMPORTANTE: Edite ${app_dir}/.env com as configurações de produção!"
        else
            warn "Arquivo .env.example não encontrado. Crie manualmente: ${app_dir}/.env"
        fi
    else
        warn "Arquivo .env já existe — não será sobrescrito."
    fi

    log "Deploy da aplicação concluído — OK"
}

# ---------------------------------------------------------------------------
# 7. Configurar PM2
# ---------------------------------------------------------------------------
configure_pm2() {
    section "7. Configurando PM2 + systemd"

    local app_dir="/opt/recreahub-api"

    log "Iniciando aplicação com PM2..."
    run "cd ${app_dir} && pm2 start ecosystem.config.js --env production"

    log "Salvando estado do PM2..."
    run "pm2 save"

    log "Configurando PM2 para inicializar com o sistema..."
    # Capturar e executar o comando de startup automaticamente
    if [ "$DRY_RUN" = false ]; then
        pm2 startup systemd -u root --hp /root | tail -1 | bash
    else
        echo -e "${YELLOW}[DRY-RUN]${RESET} pm2 startup systemd -u root --hp /root | tail -1 | bash"
    fi

    log "PM2 configurado com systemd — OK"
}

# ---------------------------------------------------------------------------
# 8. Configurar SELinux
# ---------------------------------------------------------------------------
configure_selinux() {
    section "8. Configurando SELinux"

    log "Habilitando boolean httpd_can_network_connect (permite proxy para Node.js)..."
    run "setsebool -P httpd_can_network_connect 1"

    log "Habilitando boolean httpd_can_network_relay..."
    run "setsebool -P httpd_can_network_relay 1"

    log "Verificando booleans SELinux:"
    if [ "$DRY_RUN" = false ]; then
        getsebool httpd_can_network_connect
        getsebool httpd_can_network_relay
    fi

    log "SELinux configurado — OK"
    log "Dica: Para diagnosticar bloqueios SELinux use: ausearch -m avc -ts recent | audit2allow -a"
}

# ---------------------------------------------------------------------------
# 9. Configurar firewalld
# ---------------------------------------------------------------------------
configure_firewall() {
    section "9. Configurando firewalld"

    log "Abrindo porta HTTP (80)..."
    run "firewall-cmd --permanent --add-service=http"

    log "Abrindo porta HTTPS (443)..."
    run "firewall-cmd --permanent --add-service=https"

    log "Abrindo porta da aplicação Node.js (${APP_PORT}/tcp)..."
    run "firewall-cmd --permanent --add-port=${APP_PORT}/tcp"

    log "Recarregando regras do firewall..."
    run "firewall-cmd --reload"

    log "Regras ativas do firewall:"
    if [ "$DRY_RUN" = false ]; then
        firewall-cmd --list-all
    fi

    log "firewalld configurado — OK"
}

# ---------------------------------------------------------------------------
# 10. Instalar e configurar Nginx
# ---------------------------------------------------------------------------
install_nginx() {
    section "10. Instalando Nginx + Certbot"

    log "Instalando Nginx (AppStream — não requer EPEL)..."
    run "dnf install -y nginx"

    log "Instalando Certbot com plugin Nginx..."
    run "dnf install -y certbot python3-certbot-nginx"

    local nginx_conf_src="${SCRIPT_DIR}/setup-nginx-almalinux9.conf"
    local nginx_conf_dst="/etc/nginx/conf.d/recreahub-api.conf"

    if [ -f "$nginx_conf_src" ]; then
        log "Copiando configuração Nginx para ${nginx_conf_dst}..."
        run "cp \"${nginx_conf_src}\" \"${nginx_conf_dst}\""
    else
        warn "Arquivo de configuração não encontrado: ${nginx_conf_src}"
        warn "Crie manualmente: ${nginx_conf_dst}"
    fi

    log "Testando configuração Nginx..."
    run "nginx -t"

    log "Habilitando e iniciando Nginx..."
    run "systemctl enable --now nginx"

    log "Nginx instalado e ativo — OK"
    log ""
    log "Para obter certificado SSL, execute:"
    log "  certbot --nginx -d api.recreahub.com.br"
}

# ---------------------------------------------------------------------------
# 11. Resumo final
# ---------------------------------------------------------------------------
print_summary() {
    section "Instalação concluída!"

    local server_ip
    server_ip=$(hostname -I | awk '{print $1}')

    echo ""
    echo -e "${BOLD}Informações do servidor:${RESET}"
    echo -e "  IP do servidor   : ${CYAN}${server_ip}${RESET}"
    echo -e "  Porta Node.js    : ${CYAN}${APP_PORT}${RESET}"
    echo -e "  Health check     : ${CYAN}http://${server_ip}:${APP_PORT}/health${RESET}"
    echo -e "  Diretório da app : ${CYAN}/opt/recreahub-api${RESET}"
    echo ""

    echo -e "${BOLD}Status PM2:${RESET}"
    pm2 status || true
    echo ""

    echo -e "${BOLD}Próximos passos:${RESET}"
    echo -e "  1. Edite o arquivo .env:  ${CYAN}nano /opt/recreahub-api/.env${RESET}"
    echo -e "  2. Reinicie a app:        ${CYAN}pm2 restart recreahub-api${RESET}"
    if [ "$NO_NGINX" = false ]; then
        echo -e "  3. Configure SSL:         ${CYAN}certbot --nginx -d api.recreahub.com.br${RESET}"
        echo -e "  4. Teste Nginx:           ${CYAN}curl http://${server_ip}/health${RESET}"
    fi
    echo ""

    echo -e "${BOLD}Comandos úteis:${RESET}"
    echo -e "  ${CYAN}pm2 logs recreahub-api${RESET}              — Ver logs em tempo real"
    echo -e "  ${CYAN}pm2 restart recreahub-api${RESET}           — Reiniciar aplicação"
    echo -e "  ${CYAN}pm2 reload recreahub-api${RESET}            — Reload sem downtime"
    echo -e "  ${CYAN}journalctl -u nginx -f${RESET}              — Logs do Nginx"
    echo -e "  ${CYAN}firewall-cmd --list-all${RESET}             — Listar regras do firewall"
    echo -e "  ${CYAN}getsebool httpd_can_network_connect${RESET} — Verificar SELinux"
    echo ""
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
main() {
    echo ""
    echo -e "${CYAN}${BOLD}============================================================${RESET}"
    echo -e "${CYAN}${BOLD}   RecreaHUB API — Setup AlmaLinux 9 / Rocky 9 / RHEL 9   ${RESET}"
    echo -e "${CYAN}${BOLD}============================================================${RESET}"

    if [ "$DRY_RUN" = true ]; then
        warn "Modo DRY-RUN ativado — nenhum comando será executado."
    fi

    check_almalinux9
    check_root
    install_base
    install_nodejs
    install_pm2
    deploy_app
    configure_pm2
    configure_selinux
    configure_firewall

    if [ "$NO_NGINX" = false ]; then
        install_nginx
    else
        warn "Instalação do Nginx pulada (--no-nginx)."
    fi

    print_summary
}

main "$@"
