# NOVA_CLI/nova_cli/local/file_manager/git_ops.py

import os
from pathlib import Path

import git

from nova_cli import config
from nova_cli.local.ui import ui

# --- GIT INTEGRATION ---
repo_path: Path = Path(os.getcwd())


def _default_commit_message() -> str:
    return "chore: update files"


try:
    repo: git.Repo = git.Repo(repo_path, search_parent_directories=True)
except git.exc.InvalidGitRepositoryError:
    repo = git.Repo.init(repo_path)
    ui.print("[dim]>> Git repository initialized.[/dim]")


def update_repo_path(new_path: str) -> None:
    """Updates the repo object when user CDs."""
    global repo, repo_path
    try:
        repo_path = Path(new_path)
        repo = git.Repo(repo_path, search_parent_directories=True)
    except Exception:
        # If user CDs into a non-git directory, keep last known repo.
        pass


def commit_changes(message: str, filepath: str | None = None, use_semantic: bool = False) -> bool:
    """
    Handles committing changes.
    Respects the GIT_AUTO_COMMIT flag from config.
    If use_semantic is True, generates a descriptive message via AI (stubbed).
    """
    try:
        if not config.GIT_AUTO_COMMIT:
            return False

        # Smart staging
        if filepath:
            try:
                rel = os.path.relpath(filepath, repo.working_dir)
                repo.git.add(rel)
            except Exception:
                repo.git.add(filepath)
        else:
            repo.git.add(u=True)

        if repo.is_dirty(untracked_files=False) or filepath:
            final_msg = f"NOVA: {message}"

            if use_semantic and filepath:
                try:
                    diff = repo.git.diff(cached=True)
                    if diff:
                        ui.print("[dim cyan]>> Generating semantic commit message...[/dim cyan]")
                        final_msg = _default_commit_message()
                        ui.print(f"[dim]>> Semantic Commit: {final_msg}[/dim]")
                except Exception:
                    pass

            repo.index.commit(final_msg)

            if not use_semantic:
                ui.print(f"[dim]>> Auto-Commit: {final_msg}[/dim]")

            if config.GIT_AUTO_PUSH:
                perform_push()

            return True

    except Exception as e:
        ui.print(f"[yellow]>> Git Error: {e}[/yellow]")

    return False


def manual_commit(message: str) -> None:
    """Forces a commit regardless of auto settings."""
    try:
        repo.git.add(".")
        if repo.is_dirty(untracked_files=True) or repo.index.diff("HEAD"):
            repo.index.commit(f"NOVA: {message}")
            ui.print(f"[green]>> Manual Commit Success: {message}[/green]")
        else:
            ui.print("[dim]>> Nothing to commit (clean working tree).[/dim]")
    except Exception as e:
        ui.print(f"[red]>> Commit Failed: {e}[/red]")


def perform_push() -> None:
    """Pushes to origin. Handles missing remotes gracefully."""
    try:
        if "origin" not in repo.remotes:
            ui.print("[yellow]>> No remote 'origin' found. Cannot push.[/yellow]")
            return

        ui.print("[dim]>> Pushing to origin...[/dim]")
        repo.remotes.origin.push()
        ui.print("[green]>> Push Complete.[/green]")
    except Exception as e:
        ui.print(f"[red]>> Push Failed: {e}[/red]")


def perform_pull() -> None:
    """Pulls from origin."""
    try:
        if "origin" not in repo.remotes:
            ui.print("[yellow]>> No remote 'origin' found. Cannot pull.[/yellow]")
            return

        ui.print("[dim]>> Pulling from origin...[/dim]")
        repo.remotes.origin.pull()
        ui.print("[green]>> Pull Complete.[/green]")
    except Exception as e:
        ui.print(f"[red]>> Pull Failed: {e}[/red]")


def git_status() -> None:
    """Prints current git status."""
    try:
        if repo.is_dirty(untracked_files=True):
            ui.print(f"[yellow]{repo.git.status()}[/yellow]")
        else:
            ui.print("[green]Git Status: Clean working tree.[/green]")
    except Exception as e:
        ui.print(f"[red]{e}[/red]")
