"""
Git pull request operations.

This module provides PR-related git workflow functions, including pushing
branches and creating pull requests via gh CLI.

Key Functions:
    - check_gh_available: Check if gh CLI is available
    - push_branch: Push branch to remote origin
    - create_pull_request: Create a PR using gh CLI
    - generate_pr_body: Generate PR description from commit groups

Usage Example:
    >>> from pathlib import Path
    >>> from persuade.git_pr import push_branch, create_pull_request
    >>>
    >>> # Push a branch
    >>> repo_path = Path("/path/to/project")
    >>> push_result = push_branch(repo_path, "persuade/sync-2024-01-15")
    >>>
    >>> # Create a PR
    >>> if push_result.success:
    ...     pr_result = create_pull_request(
    ...         repo_path,
    ...         title="chore: sync persuade config",
    ...         body="Update with latest persuade configuration."
    ...     )

Security:
    - Uses subprocess with explicit command lists (no shell=True)
    - Timeouts prevent hanging on slow network operations
"""

import subprocess
from pathlib import Path
from typing import TYPE_CHECKING

from persuade.constants import GIT_REV_PARSE_TIMEOUT
from persuade.git_workflow import GitWorkflowResult
from persuade.logging import get_logger

if TYPE_CHECKING:
    from persuade.commit_categorization import CommitGroup

logger = get_logger()


def check_gh_available() -> bool:
    """Check if gh CLI is available.

    Returns:
        True if gh is installed and available, False otherwise
    """
    try:
        result = subprocess.run(
            ["gh", "--version"],
            capture_output=True,
            timeout=GIT_REV_PARSE_TIMEOUT,
            check=False,
        )
        return result.returncode == 0
    except (FileNotFoundError, subprocess.TimeoutExpired):
        return False


def push_branch(repo_path: Path, branch_name: str) -> GitWorkflowResult:
    """Push branch to remote origin.

    Args:
        repo_path: Path to git repository
        branch_name: Branch name to push

    Returns:
        GitWorkflowResult with push status
    """
    logger.info("pushing_branch", branch=branch_name)

    try:
        result = subprocess.run(
            ["git", "push", "-u", "origin", branch_name],
            cwd=repo_path,
            capture_output=True,
            text=True,
            timeout=60,  # Push can take longer
            check=False,
        )

        if result.returncode != 0:
            return GitWorkflowResult(
                success=False,
                message=f"Failed to push branch: {result.stderr}",
                error=result.stderr,
            )

        return GitWorkflowResult(
            success=True,
            message=f"Pushed branch {branch_name} to origin",
            branch_name=branch_name,
        )

    except FileNotFoundError:
        return GitWorkflowResult(
            success=False,
            message="Git command not found",
            error="Git is not installed or not in PATH",
        )
    except subprocess.TimeoutExpired:
        return GitWorkflowResult(
            success=False,
            message="Push operation timed out",
            error="Git push timed out",
        )


def create_pull_request(
    repo_path: Path,
    title: str,
    body: str,
    base_branch: str | None = None,
) -> GitWorkflowResult:
    """Create a pull request using gh CLI.

    Args:
        repo_path: Path to git repository
        title: PR title
        body: PR body/description
        base_branch: Target branch (defaults to repo default)

    Returns:
        GitWorkflowResult with PR creation status
    """
    if not check_gh_available():
        return GitWorkflowResult(
            success=False,
            message="gh CLI is not available",
            error="Install gh CLI: https://cli.github.com/",
        )

    logger.info("creating_pull_request", title=title)

    try:
        cmd = ["gh", "pr", "create", "--title", title, "--body", body]

        if base_branch:
            cmd.extend(["--base", base_branch])

        result = subprocess.run(
            cmd,
            cwd=repo_path,
            capture_output=True,
            text=True,
            timeout=60,
            check=False,
        )

        if result.returncode != 0:
            return GitWorkflowResult(
                success=False,
                message=f"Failed to create PR: {result.stderr}",
                error=result.stderr,
            )

        # Extract PR URL from output
        pr_url = result.stdout.strip()
        logger.info("pull_request_created", url=pr_url)

        return GitWorkflowResult(
            success=True,
            message="Pull request created successfully",
            pr_url=pr_url,
        )

    except subprocess.TimeoutExpired:
        return GitWorkflowResult(
            success=False,
            message="PR creation timed out",
            error="gh pr create timed out",
        )


def generate_pr_body(
    commit_groups: list["CommitGroup"],
    ignored_files_count: int = 0,
) -> str:
    """Generate PR body/description for sync PR.

    Args:
        commit_groups: List of CommitGroup objects
        ignored_files_count: Number of files that needed force-add

    Returns:
        Formatted PR body markdown
    """
    lines = [
        "## Summary",
        "Update project with latest persuade configuration.",
        "",
        "### Changes by category:",
    ]

    for group in commit_groups:
        file_count = len(group.files)
        file_word = "file" if file_count == 1 else "files"
        # Convert commit message to past tense for PR description
        desc = group.message
        if desc.startswith("add"):
            desc = "Added" + desc[3:]
        elif desc.startswith("update"):
            desc = "Updated" + desc[6:]
        lines.append(f"- {desc} ({file_count} {file_word})")

    if ignored_files_count > 0:
        lines.extend(
            [
                "",
                f"**Note:** {ignored_files_count} files were gitignored by your project "
                "and have been force-added.",
            ]
        )

    lines.extend(
        [
            "",
            "---",
            "Generated by [persuade sync](https://github.com/stavxyz/persuade)",
        ]
    )

    return "\n".join(lines)
