# import uuid
import json
import os
import subprocess
import sys
import typer
from rich.progress import Progress, SpinnerColumn, TextColumn
from rich.console import Console
from typing import Optional
from typing_extensions import Annotated

app = typer.Typer()
err_console = Console(stderr=True)
ABS_PATH = os.path.join(os.path.dirname(__file__))


def install_req(repo_path: str, archive: str = "requirements.txt"):
    """Install dependencies from requirements.txt"""
    archive_abs_path = f"{repo_path}/{archive}"
    if os.path.exists(archive_abs_path):
        print("Instalando dependencias ", end=" ")
        try:
            command = f"pip install -r {archive_abs_path}"
            subprocess.run(command, shell=True, check=True)
            print("[OK]")
        except:
            print("[ERROR]")
    else:
        print("No hay archivo de dependencias[OK]")


def remove_garbage(repo_path: str):
    """Remove unnecessary files"""
    print("Removiendo archivos innecesarios ", end=" ")
    items = os.listdir(f"{repo_path}/")
    try:
        for item in items:
            if os.path.isfile(f"{repo_path}/{item}"):
                command = f"rm -rf {repo_path}/{item}"
                subprocess.run(command, shell=True, check=True)
        subprocess.run(f"rm -rf {repo_path}/.git", shell=True, check=True)
        subprocess.run(f"rm -rf {repo_path}/setup", shell=True, check=True)
        print("[OK]")
    except:
        print("[ERROR]")
        sys.exit(1)


def move_folders(repo_path: str):
    """Move folders to current directory"""
    print("Moviendo repositorio a carpeta actual ", end=" ")
    try:
        subprocess.run(f"mv {repo_path}/* .", shell=True, check=True)
        subprocess.run(f"rm -rf {repo_path}", shell=True, check=True)
        print("[OK]")
    except:
        print("[ERROR]")
        sys.exit(1)

def git_clone_update(url: str, branch: str, token: str = None, repo_path: str = None):
    """Clona o actualiza un repositorio Git.
    Si en local hay cambios directamente hace un hard reset y vuelve a pullear
    """
    url_old = url

    if not repo_path:
        if ".git" in url:
            repo_path = url.split(".git")[0].split("/")[-1]
        if not ".git" in url:
            repo_path = url.split("/")[-1]


    if token:
        if "github.com" in url:
            url = url.replace("github.com", f"{token}@github.com") + ".git"
        elif "gitlab.com" in url:
            url = url.replace("gitlab.com", f"oauth2:{token}@gitlab.com")+".git"
    if os.path.exists(repo_path) and os.path.exists(f"{repo_path}/.git"):
        message = f"[cyan] Actualizando {repo_path}... [/cyan]"
        command = ["git", "-C", repo_path, "pull"]
        ## Se hace un reset para obviar cambios locales
        subprocess.run(["git", "-C", repo_path, "reset", "--hard"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    else:
        message = f"[cyan] Clonando {url_old} ({branch})... [/cyan]"
        command = ["git", "clone", "--recurse-submodules", url, "-b", branch, repo_path]

    with Progress(SpinnerColumn(), TextColumn("{task.description}")) as progress:
        task = progress.add_task(description=message, total=None)

        try:
            process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            stdout, stderr = process.communicate()

            if process.returncode == 0:
                progress.update(task, description=f"[green]{message} ✔[/green]", completed=1)
            else:
                progress.update(task, description=f"[red]Error en {repo_path} ✖[/red]", completed=1)
                print(f"\n[red]Salida de Git:[/red]\n{stderr.strip()}")
                sys.exit(1)

        except Exception as e:
            progress.update(task, description=f"[red]Error en {repo_path} ✖[/red]", completed=1)
            print(f"\n[red]Error inesperado:[/red] {e}")
            sys.exit(1)


def git_update_all():
    """Update all repositories in the current directory"""
    with Progress(SpinnerColumn(), TextColumn("{task.description}")) as progress:
        for carpeta in os.listdir():
            ruta_completa = os.path.join(os.getcwd(), carpeta)
            if os.path.isdir(ruta_completa) and os.path.isdir(os.path.join(ruta_completa, ".git")):
                try:
                    message = f"[cyan] Actualizando {carpeta}... [/cyan]"
                    task = progress.add_task(description=message, total=None)
                    subprocess.run(["git", "-C", ruta_completa, "pull"], check=True)
                    progress.update(task, description=f"[green]{message} ✔[/green]", completed=1)
                except subprocess.CalledProcessError:
                    progress.update(task, description=f"[red]Error en {carpeta} ✖[/red]", completed=1)

@app.command()
def main(
    url: Annotated[Optional[str], typer.Argument(help="URL del repositorio")]=None,
    repositories: Annotated[
    Optional[str], typer.Option(help="JSON con con repositorios a clonar"),
    ] = None,
    branch: Annotated[Optional[str], typer.Option(help="Branch del repositorio")] = None,
    requirements : Annotated[
        Optional[bool], typer.Option(help="No instala dependencias"),
    ] = False,
    # update: Annotated[
    #     Optional[bool], typer.Option(help="Actualiza todos los repositorios"),
    # ] = False,
    # garbage: Annotated[
    #     Optional[bool], typer.Option(help="No elimina archivos innecesarios"),
    # ] = True,
    repopath: Annotated[
        Optional[str], typer.Option(help="Ruta del repositorio"),
    ] = None,
    token: Annotated[
        Optional[str], typer.Option(help="Token de acceso a repositorio"),
    ] = None,
):

    """Utility for cloning Git repositories, removing unnecessary files, and installing dependencies from requirements.txt."""

    # if update:
    #     git_update_all()
    #     sys.exit(0)

    if not repositories:
        """Clonado simple de un repositorio"""
        git_clone_update(url=url, branch=branch, token=token, repo_path=repopath)

        if requirements:
            install_req(repo_path=repopath)
        # if garbage:
        #     remove_garbage(repo_path=repopath)
        # if not repopath:
        #     move_folders(repo_path=repopath)
    
    if repositories:
        """
        Clonado de varios repositorios
        Formato de JSON:
        [
            {
                "url": "https://github.com/org/repo1",
                "branch": "18.0",
                "repo_path": "repo1"
            },
            {
                "url": "https://github.com/OCA/commission",
                "branch": "18.0",
                "repo_path": "oca/commission"
            }
        ]
        """
        for repo in json.loads(repositories):
            if "branch" not in repo and not branch:
                err_console.print("✖[red] Branch Not defined [/red]")
                raise typer.Exit(1)
            branch = branch if branch else repo["branch"]
            repo_path = repo["repo_path"] if "repo_path" in repo else None
            git_clone_update(url=repo["url"], branch=branch, token=token, repo_path=repo_path)
        

if __name__ == "__main__":
    app()
