from pathlib import Path
from lib.ClienteLinux import obter_cliente_linux
from lib.obter_configuracoes import obter_configuracoes
from lib.echo import echo
from lib.conectividade import (
    destinos_do_servidor_linux,
    echoar_resultados,
    montar_comando_ping,
    montar_mensagem_sem_rede,
    verificar_destinos,
)
from lib.registro_docker import REGISTRO_PADRAO


def _obter_percentual_uso_disco_raiz(saida_df):
    linhas = [linha.strip() for linha in saida_df.splitlines() if linha.strip()]

    if len(linhas) < 2:
        return None

    colunas = linhas[1].split()

    if len(colunas) < 5:
        return None

    percentual_uso = colunas[4].strip()

    if not percentual_uso.endswith("%"):
        return None

    percentual_uso = percentual_uso[:-1]

    if not percentual_uso.isdigit():
        return None

    return int(percentual_uso)


def _validar_uso_disco_servidor(cliente_linux):
    resultado = cliente_linux.executar_comando(
        "df -P /",
        disparar_excecao_se_retorno_nao_zero=False,
        echoar=False
    )

    if resultado.codigo_retorno != 0:
        return None

    percentual_uso = _obter_percentual_uso_disco_raiz(resultado.saida)

    if percentual_uso is None or percentual_uso < 80:
        return None

    echo(
        f"[WARN] Uso de disco do servidor Linux em {percentual_uso}% na particao /. "
        "Recomenda-se liberar espaco antes de continuar.",
        "warn"
    )

    if percentual_uso >= 100:
        return (
            "Servidor Linux com 100% de uso na particao /. "
            "Libere espaco antes de continuar."
        )

    return None


def _obter_registro_docker_configurado(configuracoes):
    acessos = configuracoes["acessos"] if "acessos" in configuracoes else {}
    registro = acessos.get("registroDocker") or {}

    return registro.get("endereco") or REGISTRO_PADRAO


def _validar_conectividade_servidor(cliente_linux, configuracoes):
    """
    O servidor Linux e quem baixa as imagens, entao a conectividade que importa aqui e a dele, nao
    a da maquina que dispara a implantacao. Retorna mensagem de erro somente quando nada responde.
    """

    echo("Verificando conectividade do servidor Linux com os destinos da implantacao")

    def executar(comando):
        return cliente_linux.executar_comando(
            comando,
            disparar_excecao_se_retorno_nao_zero=False,
            echoar=False
        ).codigo_retorno

    destinos = destinos_do_servidor_linux(_obter_registro_docker_configurado(configuracoes))
    resultados = verificar_destinos(executar, destinos)

    echoar_resultados(resultados, prefixo="  ")

    inacessiveis = [resultado for resultado in resultados if not resultado.tcp_ok]

    if not inacessiveis:
        return None

    ping_respondeu = executar(montar_comando_ping("google.com")) == 0

    echo(
        f"  ping google.com respondeu: {ping_respondeu} "
        "(ICMP bloqueado e comum e nao significa falta de internet)"
    )

    if len(inacessiveis) < len(resultados):
        echo(
            f"[WARN] {len(inacessiveis)} de {len(resultados)} destinos inacessiveis no servidor "
            "Linux. A implantacao continua, mas as etapas que dependem deles vao falhar.",
            "warn"
        )
        return None

    return montar_mensagem_sem_rede(resultados, ping_respondeu)


def executar_validacoes_servidor_linux(arquivo_configuracao, diretorio_scripts_implantacao):
    if not arquivo_configuracao or not Path(arquivo_configuracao).exists():
        return "Arquivo de configuracao nao informado ou inexistente"
    

    if not diretorio_scripts_implantacao or not Path(diretorio_scripts_implantacao).exists():
        return f"Diretorio de scripts de implantacao {diretorio_scripts_implantacao} nao encontrado"
    
    cliente_linux = obter_cliente_linux(arquivo_configuracao)


    if not cliente_linux or not cliente_linux.conexao_ok():
        return f"Não foi possível conectar ao servidor Linux. Dados de conexao: {cliente_linux.obter_dados_cliente_linux()}"
    
    configuracoes = obter_configuracoes(arquivo_configuracao)    
    
    usuario = configuracoes['acessos']['servidorLinux']['usuario']

    if cliente_linux.executar_comando(
        "command -v docker >/dev/null 2>&1",
        disparar_excecao_se_retorno_nao_zero=False
    ).codigo_retorno != 0:
        return "docker nao esta instalado"
    
    if cliente_linux.executar_comando(
        f"id -u {usuario} >/dev/null 2>&1",
        disparar_excecao_se_retorno_nao_zero=False
    ).codigo_retorno != 0:
        return f"Usuario {usuario} nao encontrado"
    
    if cliente_linux.executar_comando(
        f"id -nG {usuario} | tr ' ' '\\n' | grep -Fx docker >/dev/null 2>&1",
        disparar_excecao_se_retorno_nao_zero=False
    ).codigo_retorno != 0:
        return f"Usuario {usuario} nao pertence ao grupo docker"

    mensagem_erro = _validar_uso_disco_servidor(cliente_linux)

    if mensagem_erro:
        return mensagem_erro

    mensagem_erro = _validar_conectividade_servidor(cliente_linux, configuracoes)

    if mensagem_erro:
        return mensagem_erro

    return None
