"""Git operations: branch detection, push with rebase-retry, GitHub remote setup."""

import os
import subprocess
import sys
from pathlib import Path
from typing import Optional

from common import log


def get_current_branch(project_dir: Path) -> str:
    """Return the current Git branch name, defaulting to ``main``."""
    try:
        result = subprocess.run(
            ["git", "rev-parse", "--abbrev-ref", "HEAD"],
            cwd=str(project_dir), capture_output=True, text=True, timeout=10,
        )
        branch = result.stdout.strip()
        if branch and branch != "HEAD":
            return branch
    except Exception:
        pass
    return "main"


def has_unpushed_commits(project_dir: Path) -> bool:
    """Check whether the local branch is ahead of its remote counterpart."""
    try:
        has_commits = subprocess.run(
            ["git", "rev-parse", "HEAD"],
            cwd=str(project_dir), capture_output=True, timeout=10,
        )
        if has_commits.returncode != 0:
            return False

        branch = get_current_branch(project_dir)
        ref_check = subprocess.run(
            ["git", "rev-parse", "--verify", f"origin/{branch}"],
            cwd=str(project_dir), capture_output=True, timeout=10,
        )
        if ref_check.returncode != 0:
            return True

        subprocess.run(
            ["git", "fetch", "origin", branch, "--quiet"],
            cwd=str(project_dir), capture_output=True, timeout=30,
        )
        result = subprocess.run(
            ["git", "rev-list", "--count", f"origin/{branch}..HEAD"],
            cwd=str(project_dir), capture_output=True, text=True, timeout=10,
        )
        return int(result.stdout.strip()) > 0
    except Exception:
        return False


def push_commits(project_dir: Path, log_fh) -> bool:
    """Push local commits; auto-rebase on non-fast-forward rejection."""
    branch = get_current_branch(project_dir)
    log(log_fh, f"Pushing local commits to origin/{branch}...")
    try:
        ref_check = subprocess.run(
            ["git", "rev-parse", "--verify", f"origin/{branch}"],
            cwd=str(project_dir), capture_output=True, timeout=10,
        )
        first_push = ref_check.returncode != 0
        cmd = (["git", "push", "-u", "origin", branch]
               if first_push else ["git", "push", "origin", branch])
        result = subprocess.run(
            cmd,
            cwd=str(project_dir), capture_output=True, text=True, timeout=120,
        )
        if result.returncode == 0:
            log(log_fh, "Push succeeded.")
            return True

        if "non-fast-forward" in result.stderr or "rejected" in result.stderr:
            log(log_fh, "Push rejected (non-fast-forward) — rebasing and retrying...")
            rebase = subprocess.run(
                ["git", "pull", "--rebase", "origin", branch],
                cwd=str(project_dir), capture_output=True, text=True, timeout=60,
            )
            if rebase.returncode != 0:
                log(log_fh, f"Rebase failed: {rebase.stderr.strip()}")
                return False
            result2 = subprocess.run(
                cmd,
                cwd=str(project_dir), capture_output=True, text=True, timeout=120,
            )
            if result2.returncode == 0:
                log(log_fh, "Push succeeded (after rebase).")
                return True
            log(log_fh, f"Push failed after rebase (rc={result2.returncode}): {result2.stderr.strip()}")
            return False

        log(log_fh, f"Push failed (rc={result.returncode}): {result.stderr.strip()}")
        return False
    except Exception as e:
        log(log_fh, f"Push error: {e}")
        return False


def push_pending_commits(
    project_dir: Path,
    log_fh,
    *,
    before_push=None,
) -> bool:
    """Push if there are unpushed commits; call *before_push* callback first."""
    if not has_unpushed_commits(project_dir):
        log(log_fh, "No unpushed commits — skipping push.")
        return True
    if before_push:
        before_push()
    return push_commits(project_dir, log_fh)


def ensure_github_remote(project_dir: Path, project_id: str) -> None:
    """Create a private GitHub repo and set origin if not already configured."""
    try:
        result = subprocess.run(
            ["git", "remote", "get-url", "origin"],
            cwd=str(project_dir), capture_output=True, text=True,
        )
        if result.returncode == 0 and result.stdout.strip():
            return
    except Exception:
        pass
    try:
        create = subprocess.run(
            ["gh", "repo", "create", project_id, "--private", "--source", str(project_dir)],
            cwd=str(project_dir), capture_output=True, text=True, timeout=60,
        )
        if create.returncode == 0:
            print(f"GitHub repo created: {create.stdout.strip()}")
        elif "already exists" in create.stderr.lower():
            try:
                owner_result = subprocess.run(
                    ["gh", "api", "user", "--jq", ".login"],
                    capture_output=True, text=True, timeout=15,
                )
                gh_owner = owner_result.stdout.strip() if owner_result.returncode == 0 else "OWNER"
            except Exception:
                gh_owner = "OWNER"
            subprocess.run(
                ["git", "remote", "add", "origin", f"git@github.com:{gh_owner}/{project_id}.git"],
                cwd=str(project_dir), capture_output=True,
            )
    except Exception as e:
        print(f"warning: GitHub repo creation failed: {e}", file=sys.stderr)
