# app/main.py
import yaml
import subprocess
import platform
from flask import Flask, render_template, request, jsonify
from pysnmp.hlapi import getCmd, SnmpEngine, CommunityData, UdpTransportTarget, ContextData, ObjectType, ObjectIdentity
import os
import logging
from logging.handlers import RotatingFileHandler

app = Flask(__name__)

# ✅ LOGGING (PT-BR): Configuração para escrever em um arquivo dentro do contêiner
# Este arquivo será mapeado para /var/log/uptime.log no host pelo docker-compose.
log_file_path = '/usr/src/app/uptime.log'
handler = RotatingFileHandler(log_file_path, maxBytes=10000000, backupCount=5) # Rotação de logs: 10MB por arquivo, mantém 5 arquivos antigos.
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
app.logger.addHandler(handler)
app.logger.setLevel(logging.INFO)


snmp_engine = SnmpEngine()

def load_routers():
    """Carrega a configuração dos roteadores do arquivo hosts.yml."""
    with open('app/hosts.yml', 'r') as file:
        config = yaml.safe_load(file)
    
    routers_list = []
    if config:
        for router_id, details in config.items():
            router_data = details
            router_data['roteador'] = router_id
            routers_list.append(router_data)
    
    routers_list.sort(key=lambda x: x['displayName'])
    return routers_list

def check_host_connectivity(ip: str) -> bool:
    """Verifica a conectividade com um host usando ping."""
    param = '-n' if platform.system().lower() == 'windows' else '-c'
    command = ['ping', param, '1', '-W', '1', ip]
    try:
        response = subprocess.run(command, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=2)
        return response.returncode == 0
    except (subprocess.TimeoutExpired, FileNotFoundError):
        return False

def get_snmp_uptime(ip: str, community: str, oid: str) -> (str | None):
    """Consulta o uptime via SNMP e retorna uma string formatada."""
    errorIndication, errorStatus, errorIndex, varBinds = getCmd(
        snmp_engine,
        CommunityData(community),
        UdpTransportTarget((ip, 161), timeout=1.5, retries=1),
        ContextData(),
        ObjectType(ObjectIdentity(oid))
    )

    if errorIndication:
        app.logger.error(f"Erro de SNMP para o IP {ip}: {errorIndication}")
        return None
    elif errorStatus:
        error_message = errorStatus.prettyPrint()
        app.logger.error(f"Erro de Status SNMP para o IP {ip}: {error_message} em {errorIndex and varBinds[int(errorIndex) - 1][0] or '?'}")
        return None
    else:
        if not varBinds:
            app.logger.warning(f"Aviso de SNMP para o IP {ip}: Nenhuma variável (varBinds) foi recebida.")
            return None
        timeticks = int(varBinds[0][1])
        total_seconds = timeticks / 100
        days, rem = divmod(total_seconds, 86400)
        hours, rem = divmod(rem, 3600)
        minutes, seconds = divmod(rem, 60)
        return f"{int(days)} dias, {int(hours)}h {int(minutes)}m {int(seconds)}s"

@app.route('/')
def index():
    """Renderiza a página inicial com a lista de roteadores."""
    routers = load_routers()
    return render_template('index.html', routers=routers)

@app.route('/check_uptime', methods=['POST'])
def check_uptime():
    """Endpoint da API para verificar o status e o uptime de um roteador."""
    router_id = request.json.get('router_id')
    client_ip = request.remote_addr

    app.logger.info(f"Requisição recebida de {client_ip} para consultar o roteador '{router_id}'")

    if not router_id:
        return jsonify({'status': 'error', 'message': 'ID do roteador não fornecido.'}), 400

    routers = load_routers()
    target_router = next((r for r in routers if r['roteador'] == router_id), None)

    if not target_router:
        return jsonify({'status': 'error', 'message': 'Roteador não encontrado.'}), 404

    ip = target_router['ip']
    
    if not check_host_connectivity(ip):
        app.logger.warning(f"Falha no ping para o roteador '{router_id}' com IP {ip}. Cliente: {client_ip}")
        return jsonify({'status': 'DOWN', 'message': f'O host {ip} não está respondendo ao ping.'})

    uptime = get_snmp_uptime(ip, target_router['community'], target_router['oid'])
    
    if uptime:
        app.logger.info(f"Uptime para '{router_id}' ({ip}) obtido com sucesso: {uptime}. Cliente: {client_ip}")
        return jsonify({'status': 'UP', 'uptime': uptime})
    else:
        app.logger.error(f"Consulta SNMP falhou para o roteador '{router_id}' com IP {ip} após ping bem-sucedido. Cliente: {client_ip}")
        return jsonify({'status': 'ERROR', 'message': f'O host {ip} está online, mas a consulta SNMP falhou. Verifique a community e as regras de firewall/ACL.'})
