import os
import sys
import subprocess
from pathlib import Path
import typer
from pyfiglet import Figlet  # Keep this import
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn
from git import Repo

console = Console()
# --- CHANGED ---
app = typer.Typer(add_completion=False, help="pivvo: Initialize, manage, and automate Python projects.")

# --- CHANGED ---
pivvo_ERROR_LOG = "pivvo-error.log"

def log_error_details(e: subprocess.CalledProcessError):
    """Writes the stdout and stderr from a failed subprocess to a log file."""
    # 'w' mode truncates (clears) the file if it already exists.
    # --- CHANGED ---
    with open(pivvo_ERROR_LOG, "w", encoding="utf-8") as f:
        f.write("--- pivvo FAILED COMMAND ---\n")
        f.write(f"Command: {' '.join(e.cmd)}\n\n")
        f.write("--- STDOUT ---\n")
        f.write(e.stdout + "\n\n")
        f.write("--- STDERR ---\n")
        f.write(e.stderr + "\n")


def find_venv_path(start_path: Path = None) -> Path | None:
    """Find the Python executable in a virtual environment by traversing up the directory tree."""
    if start_path is None:
        start_path = Path.cwd()
    current = start_path
    while True:
        venv_path = current / "venv"
        python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
        if python_exec.exists():
            return python_exec
        parent = current.parent
        if parent == current:  # reached root
            break
        current = parent
    return None


@app.callback(invoke_without_command=True)
def main_callback(ctx: typer.Context):
    """Show banner or help."""
    f = Figlet(font="slant")
    # --- CHANGED ---
    console.print(f.renderText("Pivvo").rstrip(), style="bold green")
    if ctx.invoked_subcommand is None:
        # --- CHANGED ---
        console.print("[yellow]Use [bold]pivvo --help[/bold] to view commands.[/yellow]")


@app.command(help="Initialize a new project directory with git, venv, and basic files.")
def init(project_name: str):
    project_path = Path(project_name)
    if project_path.exists():
        console.print(f"[red]{project_path} already exists[/red]")
        raise typer.Exit(1)

    with Progress(SpinnerColumn(), TextColumn("[bold blue]{task.description}"), transient=True, console=console) as progress:
        task = progress.add_task("Creating project structure...", total=None)
        try:
            (project_path).mkdir(parents=True)
            (project_path / "__init__.py").touch()
            # --- CHANGED ---
            (project_path / "README.md").write_text(f"# {project_name}\nGenerated by pivvo")
            (project_path / ".gitignore").write_text("__pycache__\n*.pyc\nvenv/\n")
            
            subprocess.run(
                [sys.executable, "-m", "venv", str(project_path / "venv")],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
                text=True,
                encoding='utf-8'
            )

            try:
                Repo.init(project_path)
            except Exception as e:
                log_error_details(subprocess.CalledProcessError(1, ["git", "init"], "", str(e)))
                console.print(f"[red]❌ Git initialization failed. Check {pivvo_ERROR_LOG} for details.[/red]")
                raise typer.Exit(1)

            progress.stop_task(task)
            
        except subprocess.CalledProcessError as e:
            progress.stop_task(task)
            log_error_details(e)
            # --- CHANGED ---
            console.print(f"[red]❌ Project init failed. Check {pivvo_ERROR_LOG} for details.[/red]")
            raise typer.Exit(1)

    console.print(f"[green]✅ {project_name} initialized successfully[/green]")


@app.command("install-deps", help="Install dependencies inside the virtual environment.")
def install_deps(
    packages: list[str] = typer.Argument(None, help="Packages to install."),
    file: Path = typer.Option(None, "--file", "-f", help="Path to requirements file."),
):
    venv_path = Path.cwd() / "venv"
    python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")

    if not python_exec.exists():
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    with Progress(SpinnerColumn(), TextColumn("[bold blue]{task.description}"), transient=True, console=console) as progress:
        task = progress.add_task("Installing dependencies...", total=None)
        
        cmd = [str(python_exec), "-m", "pip", "install"]
        
        try:
            if file:
                console.print(f"[cyan]Installing from {file}[/cyan]")
                cmd.extend(["-r", str(file)])
            elif packages:
                console.print(f"[cyan]Installing packages: {' '.join(packages)}[/cyan]")
                cmd.extend(packages)
            elif Path("requirements.txt").exists():
                console.print("[cyan]Installing from requirements.txt[/cyan]")
                cmd.extend(["-r", "requirements.txt"])
            else:
                console.print("[red]No packages or requirements file found.[/red]")
                raise typer.Exit(1)

            subprocess.run(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
                text=True,
                encoding='utf-8'
            )
            
            progress.stop_task(task)
            console.print("[green]✅ Dependencies installed successfully.[/green]")
        
        except subprocess.CalledProcessError as e:
            progress.stop_task(task)
            log_error_details(e)
            # --- CHANGED ---
            console.print(f"[red]❌ Installation failed. Check {pivvo_ERROR_LOG} for details.[/red]")


@app.command(help="Run a Python script inside the project's virtual environment.")
def run(file: str = typer.Argument(..., help="Script file to execute.")):
    python_exec = find_venv_path()
    if python_exec is None:
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    script_path = Path(file)
    if not script_path.exists():
        console.print(f"[red]{script_path} not found[/red]")
        raise typer.Exit(1)

    try:
        subprocess.check_call([str(python_exec), str(script_path)])
        console.print("[green]✅ Script executed successfully.[/green]")
    except subprocess.CalledProcessError as e:
        log_error_details(e)
        console.print(f"[red]❌ Script execution failed. Check {pivvo_ERROR_LOG} for details.[/red]")
        raise typer.Exit(1)


@app.command(help="List installed packages inside venv.")
def list():
    venv_path = Path.cwd() / "venv"
    python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
    if not python_exec.exists():
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    subprocess.run([str(python_exec), "-m", "pip", "list"])


@app.command(help="Freeze installed packages to requirements.txt.")
def freeze():
    venv_path = Path.cwd() / "venv"
    python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
    if not python_exec.exists():
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    with open("requirements.txt", "w") as f:
        subprocess.run([str(python_exec), "-m", "pip", "freeze"], stdout=f)
    console.print("[green]✅ requirements.txt updated[/green]")


@app.command(help="Upgrade all dependencies to latest versions.")
def upgrade():
    venv_path = Path.cwd() / "venv"
    python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")
    req_file = Path("requirements.txt")

    if not python_exec.exists():
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)
    if not req_file.exists():
        console.print("[red]requirements.txt not found.[/red]")
        raise typer.Exit(1)

    with Progress(SpinnerColumn(), TextColumn("[bold blue]{task.description}"), transient=True, console=console) as progress:
        task = progress.add_task("Upgrading dependencies...", total=None)
        try:
            subprocess.run(
                [str(python_exec), "-m", "pip", "install", "--upgrade", "-r", str(req_file)],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
                text=True,
                encoding='utf-8'
            )
            progress.stop_task(task)
            console.print("[green]✅ All dependencies upgraded successfully.[/green]")
        
        except subprocess.CalledProcessError as e:
            progress.stop_task(task)
            log_error_details(e)
            # --- CHANGED ---
            console.print(f"[red]❌ Upgrade failed. Check {pivvo_ERROR_LOG} for details.[/red]")


@app.command(help="Uninstall a package and update requirements.txt.")
def remove(package: str):
    venv_path = Path.cwd() / "venv"
    python_exec = venv_path / ("Scripts/python.exe" if os.name == "nt" else "bin/python")

    if not python_exec.exists():
        console.print("[red]No virtual environment found.[/red]")
        raise typer.Exit(1)

    with Progress(SpinnerColumn(), TextColumn("[bold blue]{task.description}"), transient=True, console=console) as progress:
        task = progress.add_task(f"Removing {package}...", total=None)
        try:
            subprocess.run(
                [str(python_exec), "-m", "pip", "uninstall", "-y", package],
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                check=True,
                text=True,
                encoding='utf-8'
            )
            progress.stop_task(task)
            console.print(f"[green]✅ {package} uninstalled successfully.[/green]")
        
        except subprocess.CalledProcessError as e:
            progress.stop_task(task)
            log_error_details(e)
            # --- CHANGED ---
            console.print(f"[red]❌ Failed to uninstall {package}. Check {pivvo_ERROR_LOG} for details.[/red]")
            raise typer.Exit(1)

    req_file = Path("requirements.txt")
    if req_file.exists():
        lines = [line.strip() for line in req_file.read_text().splitlines()]
        updated = [line for line in lines if not line.lower().startswith(package.lower())]
        req_file.write_text("\n".join(updated) + "\n")
        console.print(f"[green]📄 requirements.txt updated (removed {package}).[/green]")


if __name__ == "__main__":
    app()