import subprocess
import os
import sys
import signal
import threading
import time

class Cores:
    """Classe para definir cores para saída no terminal."""
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'

services = ["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.OKBLUE}{mensagem} {spinner[idx]}{Cores.ENDC}", end='', flush=True)
        idx = (idx + 1) % len(spinner)
        time.sleep(0.1)
    print("\r" + " " * (len(mensagem) + 2), end='\r')

def run_command(command, docker_path):
    """
    Executa um comando no terminal.

    Args:
        command (str): O comando a ser executado.
        docker_path (str): O caminho onde o comando deve ser executado.
    
    Raises:
        subprocess.CalledProcessError: Se o comando retornar um código de erro.
    """
    evento_concluido = threading.Event()
    spinner_thread = threading.Thread(target=mostrar_spinner, args=("A trabalhar...", evento_concluido))
    spinner_thread.start()

    def executar_comando():
        nonlocal result
        print(f"{Cores.BOLD}{Cores.OKBLUE}A executar: {command}{Cores.ENDC}")
        result = subprocess.run(command, shell=True, cwd=docker_path, capture_output=True, text=True)

    result = None
    command_thread = threading.Thread(target=executar_comando)
    command_thread.start()
    command_thread.join()

    evento_concluido.set()
    spinner_thread.join()

    if result.stdout:
        print(result.stdout)
    if result.stderr:
        print(f"{Cores.WARNING}{result.stderr}{Cores.ENDC}")
    
    if result.returncode != 0:
        raise subprocess.CalledProcessError(result.returncode, command)

def check_and_remove_path(service_name, path, docker_path):
    """
    Verifica se um caminho existe e, em caso afirmativo, o remove.

    Args:
        service_name (str): O nome do serviço Docker.
        path (str): O caminho a ser verificado e removido.
        docker_path (str): O caminho onde o comando Docker deve ser executado.
    
    Returns:
        bool: True se o caminho existia e foi removido, False caso contrário.
    """
    check_command = f"docker compose exec -T {service_name} test -e {path}"
    remove_command = f"docker compose exec -T {service_name} rm -rf {path}"
    try:
        run_command(check_command, docker_path)
        run_command(remove_command, docker_path)
        return True
    except subprocess.CalledProcessError:
        return False

def remove_vendor_and_composer_lock(service_name, docker_path):
    """
    Remove a pasta 'vendor' e o arquivo 'composer.lock' de um serviço Docker, se existirem.

    Args:
        service_name (str): O nome do serviço Docker.
        docker_path (str): O caminho onde o comando Docker deve ser executado.
    """
    print(f"\n{Cores.OKBLUE}A verificar e remover 'vendor' e 'composer.lock' para {service_name}...{Cores.ENDC}")

    if service_name in ["backoffice-marketplace", "bi"]:
        vendor_path = "/shared/common_dependencies/vendor"
        composer_lock_path = "/shared/common_dependencies/composer.lock"
    else:
        vendor_path = "/var/www/html/vendor"
        composer_lock_path = "/var/www/html/composer.lock"
    
    vendor_removed = check_and_remove_path(service_name, vendor_path, docker_path)
    composer_lock_removed = check_and_remove_path(service_name, composer_lock_path, docker_path)
    
    if vendor_removed or composer_lock_removed:
        print(f"{Cores.OKGREEN}Pasta 'vendor' e arquivo 'composer.lock' removidos para {service_name}.{Cores.ENDC}")
    else:
        print(f"{Cores.WARNING}Nenhuma pasta 'vendor' ou arquivo 'composer.lock' encontrados para {service_name}.{Cores.ENDC}")

def main():
    """
    Função principal que coordena a remoção das dependências do Composer.
    """
    def interromper_processo(signal_received, frame):
        print(f"\n{Cores.FAIL}Processo interrompido pelo utilizador.{Cores.ENDC}")
        sys.exit(0)

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

    print(f"{Cores.OKGREEN}Iniciando a limpeza das dependências do Composer...{Cores.ENDC}")
    docker_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'docker')
    
    for service in services:
        remove_vendor_and_composer_lock(service, docker_path)

    print(f"\n{Cores.OKGREEN}Limpeza de dependências concluída com sucesso!{Cores.ENDC}")

if __name__ == "__main__":
    main()
