import sys
import re
import yaml
import os
from lib.ClienteLinux import obter_cliente_linux
import tempfile
import subprocess
from lib.shared_network import garantir_shared_network, conectar_container_shared_network
from lib.nomes_containers import (
    obter_nome_container_api_gateway,
    obter_nome_container_api_gateway_mtls_proxy,
    obter_nome_container_enterprise,
)
from lib.rede_externa import (
    deve_forcar_uso_rede_externa,
    obter_host_porta_enterprise_para_api_gateway,
)
from lib.substituir_placeholders import substituir_placeholders_arquivo


def _obter_host_porta_backend_enterprise(configuracoes):
    return obter_host_porta_enterprise_para_api_gateway(configuracoes)

def ajustar_enderecos_backends(
    endereco_arquivo_config,
    configuracoes,
    substituir=False
):
    host_enterprise, porta_enterprise = _obter_host_porta_backend_enterprise(configuracoes)
    conteudo_arquivo = ""

    with open(endereco_arquivo_config, 'r') as arquivo:
        conteudo_arquivo = arquivo.read()

    conteudo_arquivo = re.sub(
        pattern=r"\$HOST_ENTERPRISE",
        repl=host_enterprise,
        string=conteudo_arquivo
    )

    conteudo_arquivo = re.sub(
        pattern=r"\$PORTA_ENTERPRISE",
        repl=porta_enterprise,
        string=conteudo_arquivo
    )

    conteudo_arquivo = re.sub(
        pattern=r"\$HOST_REST",
        repl=[x for x in configuracoes["api-gateway"]["backends"] if x["nome"] == "Rest"][0]["host"],
        string=conteudo_arquivo
    )

    conteudo_arquivo = re.sub(
        pattern=r"\$PORTA_REST",
        repl=[x for x in configuracoes["api-gateway"]["backends"] if x["nome"] == "Rest"][0]["porta"],
        string=conteudo_arquivo
    )

    if not substituir:

        return conteudo_arquivo
    
    with open(endereco_arquivo_config, 'w') as arquivo:
        arquivo.write(conteudo_arquivo)

    return None



def escrever_conteudo_docker_compose(conteudo, endereco_arquivo):
    with open(endereco_arquivo, 'w') as arquivo:
        yaml.dump(conteudo, arquivo, sort_keys=False)

        

def executar_configuracao_completa(configuracoes, diretorio_scripts_implantacao):
    diretorio_api_gateway = os.path.join(diretorio_scripts_implantacao,  "api-gateway")
    cliente_linux = obter_cliente_linux(configuracoes=configuracoes)

    usuario = configuracoes['acessos']['servidorLinux']['usuario']
    

    if not os.path.exists(diretorio_api_gateway):
        os.mkdir(diretorio_api_gateway)

    cliente_linux.executar_comando(f"mkdir -p /home/{usuario}/api-gateway")
    cliente_linux.executar_comando(f"mkdir -p /home/{usuario}/api-gateway/config")
    cliente_linux.executar_comando(f"mkdir -p /home/{usuario}/api-gateway/docker-entrypoint.d")
    cliente_linux.executar_comando(f"mkdir -p /home/{usuario}/api-gateway/logs")

    def ajustar_enderecos_backends():
        endereco_arquivo_config = f'/home/{usuario}/api-gateway/config/api-backends.conf'
        host_enterprise, porta_enterprise = _obter_host_porta_backend_enterprise(configuracoes)

        cliente_linux.executar_comando(r"sed -i 's,\$HOST_ENTERPRISE,{host_enterprise},g' {arquivo_config}".format(
            host_enterprise = host_enterprise,
            arquivo_config = endereco_arquivo_config
        ))

        
        cliente_linux.executar_comando(r"sed -i 's,\$PORTA_ENTERPRISE,{host_enterprise},g' {arquivo_config}".format(
            host_enterprise = porta_enterprise,
            arquivo_config = endereco_arquivo_config
        ))

        cliente_linux.executar_comando(r"sed -i 's,\$HOST_REST,{host_enterprise},g' {arquivo_config}".format(
            host_enterprise = [x for x in configuracoes["api-gateway"]["backends"] if x["nome"] == "Rest"][0]["host"],
            arquivo_config = endereco_arquivo_config
        ))

        cliente_linux.executar_comando(r"sed -i 's,\$PORTA_REST,{host_enterprise},g' {arquivo_config}".format(
            host_enterprise = [x for x in configuracoes["api-gateway"]["backends"] if x["nome"] == "Rest"][0]["porta"],
            arquivo_config = endereco_arquivo_config
        ))

    def copiar_arquivos_config():
        
        arquivos_config = []

        for root,dir,files in os.walk(os.path.join(diretorio_api_gateway, "config")):
            for file in files:
                if file.endswith(".conf"):
                    arquivos_config.append(os.path.join(root, file))

        

        for arquivo in arquivos_config:
            cliente_linux.copiar_arquivo(
                arquivo, 
                f'/home/{usuario}/api-gateway/config/{os.path.basename(arquivo)}')

            
    def copiar_docker_entrypoint_scripts():
        endereco_script = os.path.join(diretorio_api_gateway, "docker-entrypoint.d", "40-excluir-default.conf.sh")
        dos2unix = os.path.join(diretorio_scripts_implantacao, "dos2unix.exe")

        subprocess.run([dos2unix, endereco_script])
        
        cliente_linux.copiar_arquivo(
            endereco_script,
            f'/home/{usuario}/api-gateway/docker-entrypoint.d/40-excluir-default.conf.sh'
        )

        cliente_linux.executar_comando(f"chmod +x /home/{usuario}/api-gateway/docker-entrypoint.d/40-excluir-default.conf.sh")

    def ajustar_docker_compose():
        pasta_api_gateway = os.path.join(diretorio_scripts_implantacao,  "api-gateway")
        caminho_docker_compose = os.path.join(pasta_api_gateway, "docker-compose-api-gateway.yml")
        caminho_docker_compose_mtls = os.path.join(pasta_api_gateway, "docker-compose-api-gateway-mtls.yml")
   
        if configuracoes["api-gateway"]["mtls"]["configurar"]:
            docker_compose = caminho_docker_compose_mtls
        else:
            docker_compose = caminho_docker_compose

        cliente_linux.copiar_arquivo(docker_compose, f'/home/{usuario}/api-gateway/docker-compose.yml')

        substituicoes = {
            r"\$API_GATEWAY_PORTA": configuracoes["api-gateway"]["porta"],
            r"\$NOME_CONTAINER_API_GATEWAY": obter_nome_container_api_gateway(configuracoes),
        }

        if configuracoes["api-gateway"]["mtls"]["configurar"]:
            substituicoes[r"\$NOME_CONTAINER_API_GATEWAY_MTLS_PROXY"] = (
                obter_nome_container_api_gateway_mtls_proxy(configuracoes)
            )

        substituir_placeholders_arquivo(
            cliente_linux,
            f"/home/{usuario}/api-gateway/docker-compose.yml",
            substituicoes
        )
        
    def copiar_certificados_mtls():
        if not configuracoes["api-gateway"]["mtls"]["configurar"]:
            return
        
        pasta_api_gateway = os.path.join(diretorio_scripts_implantacao,  "api-gateway")
        
        pastaCertificados = 'C:\\microuniversoWeb\\certificados'
        pastaCertificadosApiGateway = os.path.join(pastaCertificados, "apigateway")
        if  not os.path.exists(pastaCertificados):
            os.mkdir(pastaCertificados)
        if not os.path.exists(pastaCertificadosApiGateway):
            os.mkdir(pastaCertificadosApiGateway)
            
        
        caminho_certificado = configuracoes["api-gateway"]["mtls"]["certificados"]["enderecoCrt"]
        caminho_chave = configuracoes["api-gateway"]["mtls"]["certificados"]["enderecoKey"]
        
        caminho_itau_cert = os.path.join(pasta_api_gateway, "certs", "itau-ca.pem")
        
        cliente_linux.executar_comando(f"mkdir -p /home/{usuario}/api-gateway/certs")
        
        cliente_linux.copiar_arquivo(
            caminho_certificado,
            f'/home/{usuario}/api-gateway/certs/server.crt'
        )

        cliente_linux.copiar_arquivo(
            caminho_chave,
            f'/home/{usuario}/api-gateway/certs/server.key'
        )
        
        cliente_linux.copiar_arquivo(
            caminho_itau_cert,  
            f'/home/{usuario}/api-gateway/certs/itau-ca.pem'
        )
        

    def parar_e_subir_container():
        garantir_shared_network(cliente_linux)
        nome_container_api_gateway = obter_nome_container_api_gateway(configuracoes)
        nome_container_api_gateway_mtls_proxy = obter_nome_container_api_gateway_mtls_proxy(configuracoes)
        nome_container_enterprise = obter_nome_container_enterprise(configuracoes)
        cliente_linux.executar_comando(f"docker rm -f {nome_container_api_gateway}")
        cliente_linux.executar_comando(f"docker compose -f /home/{usuario}/api-gateway/docker-compose.yml down")
        cliente_linux.executar_comando(f"docker compose -f /home/{usuario}/api-gateway/docker-compose.yml pull")
        cliente_linux.executar_comando(f"docker compose -f /home/{usuario}/api-gateway/docker-compose.yml up -d")

        if not deve_forcar_uso_rede_externa(configuracoes):
            conectar_container_shared_network(cliente_linux, nome_container_enterprise, reiniciar_apos_conexao=True)
            conectar_container_shared_network(
                cliente_linux,
                nome_container_api_gateway,
                reiniciar_apos_conexao=True
            )

            if configuracoes["api-gateway"]["mtls"]["configurar"]:
                conectar_container_shared_network(
                    cliente_linux,
                    nome_container_api_gateway_mtls_proxy,
                    reiniciar_apos_conexao=True
                )
    
    def escrever_arquivo_local(caminho_arquivo):
        with open(caminho_arquivo, 'r', encoding='utf-8') as arquivo:
            conteudo = ''.join('    ' + line for line in arquivo)
        return conteudo
    
    def ajustar_mapeamento():
        diretorio_api_gateway = os.path.join(diretorio_scripts_implantacao,  "api-gateway")
        diretorio_perfis = os.path.join(diretorio_api_gateway, "perfis")
        
        cliente_linux.executar_comando(
            f"rm -f /home/{usuario}/api-gateway/config/mapeamentos-padrao.conf"
        )
        configurarParaPesquisaProduto = configuracoes["api-gateway"]["configurarParaPesquisaProduto"]
        configurarParaColetaPrecos = configuracoes["api-gateway"]["configurarParaColetaPrecos"]
        configurarParaLiquidacaoAutomaticaBoleto = configuracoes["api-gateway"]["configurarParaLiquidacaoAutomaticaBoleto"]
        configurarParaPixAPrazo = configuracoes["api-gateway"]["configurarParaPixAPrazo"]
        configurarmTls = configuracoes["api-gateway"]["mtls"]["configurar"]
        
        perfil_pesquisa_produto_path = os.path.join(diretorio_perfis, "mapeamento-pesquisa-produto.conf")
        conteudoPerfilPesquisaProduto = escrever_arquivo_local(perfil_pesquisa_produto_path)

        perfil_coleta_precos_path = os.path.join(diretorio_perfis, "mapeamento-coleta-precos.conf")
        conteudoPerfilColetaPrecos = escrever_arquivo_local(perfil_coleta_precos_path)
            
        perfil_liquidacao_automatica_boleto_path = os.path.join(diretorio_perfis, "mapeamento-liquidacao-automatica-boleto.conf")
        conteudoPerfilLiquidacaoAutomaticaBoleto = escrever_arquivo_local(perfil_liquidacao_automatica_boleto_path)
        
        perfil_pix_a_prazo_path = os.path.join(diretorio_perfis, "mapeamento-pix-a-prazo.conf")
        conteudoPerfilPixAPrazo = escrever_arquivo_local(perfil_pix_a_prazo_path)
        
        mapeamentoPadrao = """server {
    listen 80;
"""   
        if configurarParaPesquisaProduto:
            mapeamentoPadrao += conteudoPerfilPesquisaProduto
        
        if configurarParaColetaPrecos:
            mapeamentoPadrao += conteudoPerfilColetaPrecos
            
        if configurarParaLiquidacaoAutomaticaBoleto:
            mapeamentoPadrao += conteudoPerfilLiquidacaoAutomaticaBoleto
        
        if configurarParaPixAPrazo:
            mapeamentoPadrao += conteudoPerfilPixAPrazo
        mapeamentoPadrao += "}\n"
       
        temp_map = tempfile.NamedTemporaryFile(delete=False, suffix=".conf")
        with open(temp_map.name, 'w', encoding='utf-8') as f:
            f.write(mapeamentoPadrao)

        cliente_linux.copiar_arquivo(
            temp_map.name,
            f'/home/{usuario}/api-gateway/config/mapeamentos-padrao.conf'
        )

        # # clean up
        # os.remove(temp_map.name)

    copiar_arquivos_config()
    copiar_certificados_mtls()
    ajustar_mapeamento()
    copiar_docker_entrypoint_scripts()
    ajustar_enderecos_backends()
    if configuracoes["api-gateway"]["mtls"]["configurar"]:
        host_enterprise_mtls, porta_enterprise_mtls = _obter_host_porta_backend_enterprise(configuracoes)
        cliente_linux.executar_comando(fr"sed -i 's,\$NOME_SERVIDOR,{configuracoes['api-gateway']['mtls']['nomeServidor']},g' /home/{usuario}/api-gateway/config/mTLS.conf")
        cliente_linux.executar_comando(fr"sed -i 's,\$HOST_ENTERPRISE,{host_enterprise_mtls},g' /home/{usuario}/api-gateway/config/mTLS.conf")
        cliente_linux.executar_comando(fr"sed -i 's,\$PORTA_ENTERPRISE,{porta_enterprise_mtls},g' /home/{usuario}/api-gateway/config/mTLS.conf")
    ajustar_docker_compose()
    parar_e_subir_container()
    
