#!/bin/bash
# ============================================================
# Renovacao automatica de certificado Lets Encrypt
# Verifica validade e renova se faltar 10 dias ou menos
# Uso: /root/scripts/renew-cert.sh [--silent]
# Cron sugerido: 0 3 * * * /root/scripts/renew-cert.sh --silent
# ============================================================


########## VARIAVEIS DE AMBIENTE ##########

dominio="SEU DOMINIO AQUI"
dias_limite=10
arquivo_log="/var/log/certbot-renew.log"
modo_silencioso=false
timezone_esperado="America/Sao_Paulo"

###########################################

# --- Verificacao de parametros ---

if [ "$1" = "--silent" ] || [ "$1" = "-s" ]; then
    modo_silencioso=true
fi

# --- Funcoes auxiliares ---

registrar() {
    local nivel="$1"
    local mensagem="$2"
    local timestamp
    timestamp=$(date "+%Y-%m-%d %H:%M:%S")
    local linha="[$timestamp] [$nivel] $mensagem"

    echo "$linha" >> "$arquivo_log"

    if [ "$modo_silencioso" = false ]; then
        echo "$linha"
    fi
}

# --- Inicio da execucao ---

registrar "INFO" "============================================"
registrar "INFO" "Inicio da verificacao do certificado"
registrar "INFO" "Dominio: $dominio"
registrar "INFO" "Limite para renovacao: $dias_limite dias"
registrar "INFO" "============================================"

# --- Verificacao de timezone ---

registrar "INFO" "Verificando timezone do sistema..."

timezone_atual=$(timedatectl show --property=Timezone --value 2>/dev/null)

if [ -z "$timezone_atual" ]; then
    registrar "ALERTA" "Nao foi possivel obter o timezone atual via timedatectl."
    timezone_atual=$(cat /etc/timezone 2>/dev/null)
    if [ -z "$timezone_atual" ]; then
        registrar "ERRO" "Nao foi possivel determinar o timezone do sistema."
        registrar "INFO" "Definindo timezone para $timezone_esperado..."
        timedatectl set-timezone "$timezone_esperado" 2>&1
        if [ $? -eq 0 ]; then
            registrar "OK" "Timezone definido para $timezone_esperado com sucesso."
        else
            registrar "ERRO" "Falha ao definir timezone. Continuando com UTC."
        fi
    fi
fi

if [ "$timezone_atual" != "$timezone_esperado" ]; then
    registrar "ALERTA" "Timezone atual: $timezone_atual (esperado: $timezone_esperado)"
    registrar "INFO" "Ajustando timezone para $timezone_esperado..."
    timedatectl set-timezone "$timezone_esperado" 2>&1
    if [ $? -eq 0 ]; then
        registrar "OK" "Timezone ajustado para $timezone_esperado com sucesso."
    else
        registrar "ERRO" "Falha ao ajustar timezone. Timezone permanece: $timezone_atual"
    fi
else
    registrar "OK" "Timezone correto: $timezone_atual"
fi

# --- Verificacao de sincronizacao NTP ---

registrar "INFO" "Verificando sincronizacao de horario (NTP)..."

ntp_sincronizado=$(timedatectl show --property=NTPSynchronized --value 2>/dev/null)
ntp_servico_ativo=$(timedatectl show --property=NTP --value 2>/dev/null)

registrar "INFO" "Servico NTP ativo: $ntp_servico_ativo"
registrar "INFO" "Relogio sincronizado: $ntp_sincronizado"

if [ "$ntp_servico_ativo" != "yes" ]; then
    registrar "ALERTA" "Servico NTP nao esta ativo. Tentando habilitar..."

    if systemctl is-enabled systemd-timesyncd &>/dev/null || systemctl list-unit-files systemd-timesyncd.service &>/dev/null; then
        systemctl enable systemd-timesyncd 2>&1
        systemctl start systemd-timesyncd 2>&1
        registrar "INFO" "systemd-timesyncd habilitado e iniciado."
    elif command -v ntpd &>/dev/null; then
        systemctl enable ntp 2>&1
        systemctl start ntp 2>&1
        registrar "INFO" "ntpd habilitado e iniciado."
    elif command -v chronyd &>/dev/null; then
        systemctl enable chrony 2>&1
        systemctl start chrony 2>&1
        registrar "INFO" "chrony habilitado e iniciado."
    else
        registrar "ERRO" "Nenhum servico NTP encontrado (timesyncd/ntp/chrony)."
        registrar "ERRO" "Instale com: apt install systemd-timesyncd"
    fi

    timedatectl set-ntp true 2>&1

    # Aguarda ate 10 segundos pela sincronizacao
    tentativas=0
    max_tentativas=10
    while [ "$tentativas" -lt "$max_tentativas" ]; do
        ntp_sincronizado=$(timedatectl show --property=NTPSynchronized --value 2>/dev/null)
        if [ "$ntp_sincronizado" = "yes" ]; then
            break
        fi
        sleep 1
        tentativas=$((tentativas + 1))
    done

    ntp_sincronizado=$(timedatectl show --property=NTPSynchronized --value 2>/dev/null)
    if [ "$ntp_sincronizado" = "yes" ]; then
        registrar "OK" "Relogio sincronizado com sucesso via NTP."
    else
        registrar "ALERTA" "NTP ativado mas sincronizacao ainda pendente. Aguarde alguns minutos."
    fi
else
    registrar "OK" "Servico NTP ja esta ativo."
fi

if [ "$ntp_sincronizado" = "yes" ]; then
    registrar "OK" "Horario do sistema esta sincronizado."
else
    registrar "ALERTA" "Horario pode estar dessincronizado. Prosseguindo com cautela."
fi

registrar "INFO" "Horario atual do sistema: $(date "+%Y-%m-%d %H:%M:%S %Z")"

# --- Verificacao de dependencias ---

registrar "INFO" "Verificando dependencias..."

if ! command -v openssl &> /dev/null; then
    registrar "ERRO" "openssl nao encontrado. Instale com: apt install openssl"
    exit 1
fi

registrar "OK" "openssl encontrado: $(which openssl)"

if ! command -v certbot &> /dev/null; then
    registrar "ERRO" "certbot nao encontrado. Instale com: apt install certbot python3-certbot-apache"
    exit 1
fi

registrar "OK" "certbot encontrado: $(which certbot)"

# --- Obtencao da data de expiracao ---

registrar "INFO" "Consultando certificado de $dominio na porta 443..."

saida_openssl=$(openssl s_client -connect "$dominio":443 -servername "$dominio" </dev/null 2>/dev/null)

if [ -z "$saida_openssl" ]; then
    registrar "ERRO" "Nao foi possivel conectar em $dominio:443. Verifique se o servico esta ativo."
    exit 1
fi

registrar "OK" "Conexao com $dominio:443 realizada com sucesso."

data_expiracao=$(echo "$saida_openssl" | openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)

if [ -z "$data_expiracao" ]; then
    registrar "ERRO" "Nao foi possivel extrair a data de expiracao do certificado."
    exit 1
fi

registrar "INFO" "Data de expiracao obtida: $data_expiracao"

# --- Calculo dos dias restantes ---

timestamp_expiracao=$(date -d "$data_expiracao" +%s 2>/dev/null)

if [ -z "$timestamp_expiracao" ]; then
    registrar "ERRO" "Falha ao converter a data de expiracao: $data_expiracao"
    exit 1
fi

timestamp_atual=$(date +%s)
dias_restantes=$(( (timestamp_expiracao - timestamp_atual) / 86400 ))

registrar "INFO" "Dias restantes ate a expiracao: $dias_restantes"

# --- Decisao de renovacao ---

if [ "$dias_restantes" -le 0 ]; then
    registrar "ALERTA" "O certificado ja expirou! Iniciando renovacao imediata..."
elif [ "$dias_restantes" -le "$dias_limite" ]; then
    registrar "ALERTA" "Faltam $dias_restantes dias para expirar. Dentro do limite de $dias_limite dias."
    registrar "INFO" "Iniciando renovacao..."
else
    registrar "OK" "Certificado valido. Faltam $dias_restantes dias. Nenhuma acao necessaria."
    registrar "INFO" "Proxima verificacao sera feita na proxima execucao do cron."
    registrar "INFO" "============================================"
    registrar "INFO" "Fim da verificacao"
    registrar "INFO" "============================================"
    registrar "INFO" ""
    exit 0
fi

# --- Execucao da renovacao ---

registrar "INFO" "Executando: certbot renew"

saida_certbot=$(certbot renew --deploy-hook "systemctl reload apache2" 2>&1)
codigo_retorno=$?

registrar "INFO" "Saida do certbot:"

while IFS= read -r linha; do
    if [ -n "$linha" ]; then
        registrar "INFO" "  $linha"
    fi
done <<< "$saida_certbot"

if [ "$codigo_retorno" -eq 0 ]; then
    registrar "OK" "Renovacao concluida com sucesso."
else
    registrar "ERRO" "Falha na renovacao. Codigo de retorno do certbot: $codigo_retorno"
    registrar "ERRO" "Verifique os logs do certbot em: /var/log/letsencrypt/letsencrypt.log"
fi

# --- Verificacao pos-renovacao ---

registrar "INFO" "Verificando estado do Apache apos renovacao..."

status_apache=$(systemctl is-active apache2 2>&1)

if [ "$status_apache" = "active" ]; then
    registrar "OK" "Apache esta ativo e rodando."
else
    registrar "ERRO" "Apache nao esta ativo. Status: $status_apache"
    registrar "ERRO" "Tentando reiniciar o Apache..."
    systemctl restart apache2 2>&1
    status_apache_retry=$(systemctl is-active apache2 2>&1)
    if [ "$status_apache_retry" = "active" ]; then
        registrar "OK" "Apache reiniciado com sucesso."
    else
        registrar "ERRO" "Falha ao reiniciar o Apache. Intervencao manual necessaria."
    fi
fi

registrar "INFO" "============================================"
registrar "INFO" "Fim da verificacao"
registrar "INFO" "============================================"
registrar "INFO" ""

exit $codigo_retorno
