import subprocess
import os
import sys
import signal
import threading
import time
from pathlib import Path
import shutil

class Cores:
    """Classe para definir cores para saída no terminal."""
    VERDE_OK = '\033[92m'
    AVISO = '\033[93m'
    ERRO = '\033[91m'
    AZUL = '\033[94m'
    FIM = '\033[0m'

SERVICOS = ["backoffice-marketplace", "bi"]

def mostrar_spinner(mensagem, evento_concluido):
    """
    Mostra um spinner de carregamento na linha de comando.

    Args:
        mensagem (str): A mensagem a ser exibida junto com o spinner.
        evento_concluido (threading.Event): Evento que sinaliza a conclusão do comando.
    """
    spinner = ['|', '/', '-', '\\']
    idx = 0
    while not evento_concluido.is_set():
        print(f"\r{Cores.AZUL}{mensagem} {spinner[idx]}{Cores.FIM}", end='', flush=True)
        idx = (idx + 1) % len(spinner)
        time.sleep(0.1)
    print("\r" + " " * (len(mensagem) + 2), end='\r')

def executar_comando(comando, caminho_docker, evento_concluido):
    """
    Executa um comando no terminal.

    Args:
        comando (str): O comando a ser executado.
        caminho_docker (str): O caminho onde o comando deve ser executado.

    Returns:
        bool: True se o comando foi executado com sucesso, False caso contrário.
    """
    evento_concluido.clear()
    spinner_thread = threading.Thread(target=mostrar_spinner, args=("A processar...", evento_concluido))
    spinner_thread.start()

    try:
        print(f"{Cores.VERDE_OK}\nA executar: {comando}{Cores.FIM}")
        resultado = subprocess.run(comando, shell=True, cwd=caminho_docker, capture_output=True, text=True)

        evento_concluido.set()
        spinner_thread.join()

        if resultado.stdout:
            print(resultado.stdout)
        if resultado.stderr:
            print(f"{Cores.AVISO}{resultado.stderr}{Cores.FIM}")

        return resultado.returncode == 0
    except Exception as e:
        evento_concluido.set()
        spinner_thread.join()
        print(f"{Cores.ERRO}Erro ao executar o comando: {e}{Cores.FIM}")
        return False

def verificar_remover_diretorio_composer_lock(caminho_docker, nome_servico):
    """
    Verifica e remove o diretório composer.lock se existir para o serviço especificado.

    Args:
        caminho_docker (str): O caminho onde o comando Docker deve ser executado.
        nome_servico (str): O nome do serviço Docker.
    """
    composer_lock_path = caminho_docker / nome_servico / 'composer.lock'
    if composer_lock_path.is_dir():
        shutil.rmtree(composer_lock_path)
        print(f"{Cores.AVISO}Aviso: Removido diretório composer.lock em {nome_servico}{Cores.FIM}")

def atualizar_e_instalar_dependencias_composer(nome_servico, caminho_docker, evento_concluido):
    """
    Atualiza e instala as dependências do Composer para um serviço específico.

    Args:
        nome_servico (str): O nome do serviço Docker.
        caminho_docker (str): O caminho onde o comando Docker deve ser executado.

    Returns:
        bool: True se todas as etapas foram executadas com sucesso, False caso contrário.
    """
    verificar_remover_diretorio_composer_lock(caminho_docker, nome_servico)

    comandos = [
        (f"docker compose exec -T {nome_servico} composer update", "atualizar"),
        (f"docker compose exec -T {nome_servico} composer install", "instalar")
    ]

    for comando, acao in comandos:
        print(f"\nA {acao} dependências do Composer para {nome_servico}...")
        if not executar_comando(comando, caminho_docker, evento_concluido):
            print(f"{Cores.ERRO}Erro ao {acao} dependências para {nome_servico}. Verifique os logs acima para mais detalhes.{Cores.FIM}")
            return False

    print(f"{Cores.VERDE_OK}Dependências para {nome_servico} foram {acao}adas com sucesso.{Cores.FIM}")
    return True

def atualizar_assets(nome_servico, caminho_docker, evento_concluido):
    """
    Compila os assets no Vite para um serviço específico.
>    Args:
        nome_servico (str): O nome do serviço Docker.
        caminho_docker (str): O caminho onde o comando Docker deve ser executado.

    Returns:
        bool: True se todas as etapas foram executadas com sucesso, False caso contrário.
    """

    print(f"\nA compilar dependências npm para {nome_servico}...")
    if not executar_comando(f"docker compose exec -T {nome_servico} npm install", caminho_docker, evento_concluido):
        print(f"{Cores.ERRO}Erro a compilar dependências npm para {nome_servico}. Verifique os logs acima para mais detalhes.{Cores.FIM}")
        return False

    print(f"\nA compilar assets do Vite para {nome_servico}...")
    if not executar_comando(f"docker compose exec -T {nome_servico} npm run build", caminho_docker, evento_concluido):
        print(f"{Cores.ERRO}Erro a compilar assets para {nome_servico}. Verifique os logs acima para mais detalhes.{Cores.FIM}")
        return False

    print(f"{Cores.VERDE_OK}Dependências para {nome_servico} foram compiladas com sucesso.{Cores.FIM}")
    return True

def main():
    """
    Função principal que inicia o processo de atualização e instalação de dependências do Composer.
    """
    evento_concluido = threading.Event()

    def interromper_processo(signal_received, frame):
        evento_concluido.set()
        print(f"\n{Cores.AVISO}Processo interrompido pelo utilizador.{Cores.FIM}")
        sys.exit(0)

    signal.signal(signal.SIGINT, interromper_processo)
    signal.signal(signal.SIGTERM, interromper_processo)

    print(f"{Cores.VERDE_OK}Início do processo de atualização e instalação de dependências do Composer...{Cores.FIM}")
    caminho_docker = Path(__file__).resolve().parent.parent / 'docker'

    sucesso_global = True
    for servico in SERVICOS:
        if not atualizar_e_instalar_dependencias_composer(servico, caminho_docker, evento_concluido):
            sucesso_global = False

    for servico in SERVICOS:
        if not atualizar_assets(servico, caminho_docker, evento_concluido):
            sucesso_global = False

    if sucesso_global:
        print(f"\n{Cores.VERDE_OK}O processo de atualização e instalação de dependências foi concluído com sucesso!{Cores.FIM}")
    else:
        print(f"\n{Cores.ERRO}O processo de atualização e instalação de dependências falhou. Verifique os logs para mais detalhes.{Cores.FIM}")

if __name__ == "__main__":
    main()
