"""
Common CLI arguments and utilities for Gito commands.
"""
import contextlib
import logging
import tempfile
from typing import Iterator

import microcore as mc
import typer
from git import Repo, InvalidGitRepositoryError

from .constants import REFS_VALUE_ALL
from .utils.string import parse_refs_pair
from .env import Env


app = typer.Typer(pretty_exceptions_show_locals=False)


def args_to_target(refs, what, against) -> tuple[str | None, str | None]:
    """Convert CLI arguments to target WHAT and AGAINST refs."""
    if refs == REFS_VALUE_ALL:
        return REFS_VALUE_ALL, None
    _what, _against = parse_refs_pair(refs)
    if _what:
        if what:
            raise typer.BadParameter(
                "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--what'. Use one of them."
            )
    else:
        _what = what
    if _against:
        if against:
            raise typer.BadParameter(
                "You cannot specify both 'refs' <WHAT>..<AGAINST> and '--against'. Use one of them."
            )
    else:
        _against = against
    return _what, _against


def arg_refs() -> typer.Argument:
    return typer.Argument(
        default=None,
        help=(
            "Git refs to review, [what]..[against] (e.g., 'HEAD..HEAD~1'). "
            "If omitted, the current index (including added but not committed files) "
            "will be compared to the repository’s main branch."
        ),
    )


def arg_what() -> typer.Option:
    return typer.Option(None, "--what", "-w", help="Git ref to review")


def arg_filters() -> typer.Option:
    return typer.Option(
        "", "--filter", "-f", "--filters",
        help="""
            filter reviewed files by glob / fnmatch pattern(s),
            e.g. 'src/**/*.py', may be comma-separated
            """,
    )


def arg_out() -> typer.Option:
    return typer.Option(
        None,
        "--out", "-o", "--output",
        help="Output folder for the code review report"
    )


def arg_against() -> typer.Option:
    return typer.Option(
        None,
        "--against", "-vs", "--vs",
        help="Git ref to compare against"
    )


def arg_all() -> typer.Option:
    return typer.Option(default=False, help="Review whole codebase")


@contextlib.contextmanager
def get_repo_context(
    url: str | None,
    branch: str | None
) -> Iterator[tuple[Repo, str]]:
    """
    Context manager for handling both local and remote repositories.
    Yields a tuple of (Repo object, path to the repository)
    Args:
        url (str): URL of the remote repository. If empty, uses the local repository.
        branch (str): Branch to checkout when cloning the remote repository.
    """
    if branch == REFS_VALUE_ALL:
        branch = None
    if url:
        with tempfile.TemporaryDirectory() as temp_dir:
            logging.info(
                f"get_repo_context: "
                f"Cloning [{mc.ui.green(url)}] to {mc.utils.file_link(temp_dir)} ..."
            )
            repo = Repo.clone_from(url, branch=branch, to_path=temp_dir)
            prev_folder = Env.working_folder
            Env.working_folder = temp_dir
            try:
                yield repo, temp_dir
            finally:
                repo.close()
                Env.working_folder = prev_folder
    else:
        logging.info("get_repo_context: Using local repo...")
        try:
            repo = Repo(".")
        except InvalidGitRepositoryError:
            raise typer.BadParameter("Current folder is not a git repository.")
        try:
            yield repo, "."
        finally:
            repo.close()
