# -*- coding: utf-8 -*-

# ====================================================================
# BACKEND - SERVIDOR FLASK (API) - COM TESTE DE PING
# ====================================================================
# Agora, antes de tentar a consulta SNMP, o servidor verifica se
# o host responde ao ping para evitar timeouts desnecessários.
# ====================================================================

import yaml
from flask import Flask, jsonify, render_template
from pysnmp.hlapi import *
from datetime import timedelta
import socket
import logging
import platform
import subprocess

# Configuração básica de logging para exibir mensagens no console
# Remove handlers padrão (que vão pro stderr)
for handler in logging.root.handlers[:]:
    logging.root.removeHandler(handler)

# Cria handler para arquivo uptime.log
app_handler = logging.FileHandler('/var/log/monitor_uptime/uptime.log', encoding='utf-8')
app_handler.setLevel(logging.INFO)
app_handler.setFormatter(logging.Formatter(
    '%(asctime)s - %(levelname)s - %(message)s'
))

# Aplica no root logger
logging.root.addHandler(app_handler)
logging.root.setLevel(logging.INFO)

app = Flask(__name__)

# --- Funções de Lógica ---

def check_host_connectivity(ip: str) -> bool:
    """Verifica a conectividade com um host usando um único ping."""
    try:
        # Define o comando de ping com base no sistema operacional
        param = '-n' if platform.system().lower() == 'windows' else '-c'
        command = ['ping', param, '1', '-W', '1', ip] # -W 1 (timeout de 1s) para Linux/macOS
        if platform.system().lower() == 'windows':
            command = ['ping', param, '1', '-w', '1000', ip] # -w 1000 (timeout de 1s) para Windows

        # Executa o comando de ping, suprimindo a saída
        response = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        
        # Retorna True se o comando foi bem-sucedido (código de saída 0)
        return response.returncode == 0
    except Exception as e:
        app.logger.error(f"Erro ao executar o ping para {ip}: {e}")
        return False

def load_config():
    """Carrega a configuração dos hosts a partir do arquivo YAML."""
    try:
        with open('hosts.yml', 'r', encoding='utf-8') as file:
            return yaml.safe_load(file)
    except FileNotFoundError:
        app.logger.error("ARQUIVO DE CONFIGURAÇÃO 'hosts.yml' NÃO ENCONTRADO.")
        return {}
    except yaml.YAMLError as e:
        app.logger.error(f"ERRO DE FORMATAÇÃO NO ARQUIVO 'hosts.yml': {e}")
        return {}

def format_uptime_from_timeticks(timeticks):
    """Converte o valor de timeticks (centésimos de segundo) do SNMP para um formato legível."""
    if timeticks is None: return "N/A"
    total_seconds = int(timeticks) / 100
    td = timedelta(seconds=total_seconds)
    days, hours, remainder = td.days, 0, td.seconds
    hours, remainder = divmod(remainder, 3600)
    minutes, seconds = divmod(remainder, 60)
    return f"{days} dias, {hours:02d}h {minutes:02d}m {seconds:02d}s"

def query_snmp(ip, community, oid):
    """Executa la consulta SNMP para obter um valor de um OID específico."""
    app.logger.info(f"Iniciando consulta SNMP para {ip} com OID {oid}")
    iterator = getCmd(
        SnmpEngine(),
        CommunityData(community, mpModel=1),
        UdpTransportTarget((ip, 161), timeout=5, retries=2),
        ContextData(),
        ObjectType(ObjectIdentity(oid))
    )
    try:
        error_indication, error_status, error_index, var_binds = next(iterator)
        if error_indication:
            app.logger.error(f"Falha SNMP para {ip}: {error_indication}")
            return {"error": str(error_indication)}
        elif error_status:
            error_message = f"{error_status.prettyPrint()} at {error_index and var_binds[int(error_index) - 1][0] or '?'}"
            app.logger.error(f"Falha SNMP para {ip}: {error_message}")
            return {"error": error_message}
        else:
            app.logger.info(f"Consulta SNMP para {ip} bem-sucedida.")
            return {"value": var_binds[0][1]}
    except Exception as e:
        app.logger.error(f"Timeout ou erro inesperado na consulta SNMP para {ip}: {e}")
        return {"error": f"Nenhuma resposta SNMP de {ip}. Verifique comunidade, firewall e se o serviço SNMP está ativo no dispositivo."}

# --- Endpoints da API ---

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/api/routers', methods=['GET'])
def get_routers():
    config = load_config()
    router_list = [{"key": key, "displayName": details.get("displayName", key)} for key, details in config.items()]
    return jsonify(router_list)

@app.route('/api/uptime/<router_key>', methods=['GET'])
def get_uptime(router_key):
    config = load_config()
    host_config = config.get(router_key)
    if not host_config:
        return jsonify({"error": "Roteador não encontrado na configuração."}), 404
    
    ip, community, oid = host_config.get('ip'), host_config.get('community'), host_config.get('oid')
    if not all([ip, community, oid]):
        return jsonify({"error": "Configuração incompleta para este roteador no hosts.yml."}), 500

    # <<< NOVA VERIFICAÇÃO DE PING ADICIONADA AQUI >>>
    app.logger.info(f"Verificando conectividade com {ip}...")
    if not check_host_connectivity(ip):
        app.logger.warning(f"Host {ip} inacessível (não respondeu ao ping).")
        return jsonify({"error": "Host inacessível (não responde ao ping)."}), 500

    result = query_snmp(ip, community, oid)
    if "error" in result:
        return jsonify({"error": result["error"]}), 500
    
    human_readable_uptime = format_uptime_from_timeticks(result.get("value"))
    
    return jsonify({
        "router": host_config.get("displayName", router_key),
        "uptime": human_readable_uptime
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)

