"""CLI commands for Rhiza Tools.

This module defines the main Typer application and all command-line interface
commands for rhiza-tools. It provides commands for version bumping, coverage
badge generation, release management, and README updates.

The CLI can be used either as a standalone tool (`rhiza-tools`) or as a
subcommand of the rhiza CLI (`rhiza tools`).

Example:
    Bump version to a specific version::

        $ rhiza-tools bump 1.2.3
        $ rhiza tools bump 1.2.3

    Bump version interactively::

        $ rhiza-tools bump

    Generate a coverage badge::

        $ rhiza-tools generate-coverage-badge --coverage-json _tests/coverage.json

    Update README with make help output::

        $ rhiza-tools update-readme
"""

from pathlib import Path
from typing import Annotated

import typer

from rhiza_tools import __version__

from .commands.analyze_benchmarks import analyze_benchmarks_command
from .commands.bump import bump_command
from .commands.generate_badge import generate_coverage_badge_command
from .commands.update_readme import update_readme_command
from .commands.version_matrix import version_matrix_command


def version_callback(value: bool) -> None:
    """Display the version and exit."""
    if value:
        typer.echo(f"rhiza-tools version {__version__}")
        raise typer.Exit()


app = typer.Typer(help="Rhiza Tools - Extra utilities for Rhiza.")


@app.callback()
def main(
    version: bool = typer.Option(
        None,
        "--version",
        help="Show the version and exit.",
        callback=version_callback,
        is_eager=True,
    ),
) -> None:
    """Rhiza Tools - Extra utilities for Rhiza."""
    pass


@app.command()
def bump(
    version: str | None = typer.Argument(None, help="The version to bump to (e.g., 1.0.1, major, minor, patch, etc)"),
    dry_run: bool = typer.Option(False, "--dry-run", help="Print what would happen without doing it."),
    commit: bool = typer.Option(False, "--commit", help="Commit the changes to git."),
    allow_dirty: bool = typer.Option(
        False, "--allow-dirty", help="Allow bumping even if the working directory is dirty."
    ),
    verbose: bool = typer.Option(False, "--verbose", "-v", help="Show detailed output from bump-my-version."),
) -> None:
    """Bump the version of the project.

    This command updates the version in pyproject.toml using semantic versioning.
    You can provide an explicit version number, a bump type (patch, minor, major),
    or leave it blank for an interactive prompt.

    Args:
        version: The version to bump to. Can be an explicit version (e.g., "1.2.3"),
            a bump type ("patch", "minor", "major"), a prerelease type
            ("alpha", "beta", "rc", "dev"), or None for interactive selection.
        dry_run: If True, show what would change without actually changing anything.
        commit: If True, automatically commit the version change to git.
        allow_dirty: If True, allow bumping even with uncommitted changes.
        verbose: If True, show detailed output from the bump-my-version tool.

    Example:
        Bump to a specific version::

            $ rhiza-tools bump 2.0.0

        Bump patch version (1.2.3 -> 1.2.4)::

            $ rhiza-tools bump patch

        Preview changes without applying them::

            $ rhiza-tools bump minor --dry-run

        Interactive version selection::

            $ rhiza-tools bump
    """
    bump_command(version, dry_run, commit, allow_dirty, verbose)


@app.command()
def generate_coverage_badge(
    coverage_json: Annotated[
        Path,
        typer.Option(
            "--coverage-json",
            help="Path to coverage.json file",
        ),
    ] = Path("_tests/coverage.json"),
    output: Annotated[
        Path,
        typer.Option(
            help="Path to output badge JSON",
        ),
    ] = Path("_book/tests/coverage-badge.json"),
) -> None:
    """Generate a coverage badge for the project.

    Reads a coverage report JSON file and creates a shields.io endpoint JSON file
    for displaying a coverage badge. The badge color automatically adjusts based
    on the coverage percentage.

    Args:
        coverage_json: Path to the coverage.json file generated by pytest-cov.
        output: Path where the badge JSON file should be written.

    Example:
        Generate badge with default paths::

            $ rhiza-tools generate-coverage-badge

        Generate badge with custom paths::

            $ rhiza-tools generate-coverage-badge \
                --coverage-json tests/coverage.json \
                --output assets/badge.json
    """
    generate_coverage_badge_command(coverage_json_path=coverage_json, output_path=output)


@app.command()
def release(
    dry_run: bool = typer.Option(False, "--dry-run", help="Print what would happen without doing it."),
) -> None:
    """Create a git tag and push to remote to trigger the release workflow.

    This command creates a git tag based on the current version and pushes it
    to the remote repository, which triggers the automated release workflow.

    Args:
        dry_run: If True, show what would happen without actually creating or
            pushing the tag.

    Example:
        Create and push a release tag::

            $ rhiza-tools release

        Preview what would happen::

            $ rhiza-tools release --dry-run
    """
    if dry_run:
        typer.echo("Would create and push release tag")
    else:
        typer.echo("Creating and pushing release tag")
        # Implement actual release logic here (port from release.sh)


@app.command(name="update-readme")
def update_readme(
    dry_run: bool = typer.Option(False, "--dry-run", help="Print what would happen without doing it."),
) -> None:
    """Update README.md with the current output from `make help`.

    This command runs `make help` and updates the README.md file with the current
    help output, keeping the documentation in sync with available Make targets.

    Args:
        dry_run: If True, show the help output that would be inserted without
            actually modifying README.md.

    Example:
        Update README with make help output::

            $ rhiza-tools update-readme

        Preview changes without modifying README::

            $ rhiza-tools update-readme --dry-run
    """
    update_readme_command(dry_run)


@app.command(name="version-matrix")
def version_matrix(
    pyproject: Annotated[
        Path,
        typer.Option(
            "--pyproject",
            help="Path to pyproject.toml file",
        ),
    ] = Path("pyproject.toml"),
    candidates: Annotated[
        str | None,
        typer.Option(
            "--candidates",
            help="Comma-separated list of candidate Python versions (e.g., '3.11,3.12,3.13')",
        ),
    ] = None,
) -> None:
    """Emit supported Python versions from pyproject.toml as JSON.

    This command reads the requires-python field from pyproject.toml and outputs
    a JSON array of Python versions that satisfy the constraint. This is primarily
    used in GitHub Actions to compute the test matrix.

    Args:
        pyproject: Path to the pyproject.toml file.
        candidates: Comma-separated list of candidate Python versions to evaluate.
            Defaults to "3.11,3.12,3.13,3.14".

    Example:
        Get supported versions with defaults::

            $ rhiza-tools version-matrix
            ["3.11", "3.12"]

        Use custom pyproject.toml path::

            $ rhiza-tools version-matrix --pyproject /path/to/pyproject.toml

        Use custom candidates::

            $ rhiza-tools version-matrix --candidates "3.10,3.11,3.12"
    """
    candidates_list = None
    if candidates:
        candidates_list = [v.strip() for v in candidates.split(",")]

    version_matrix_command(pyproject_path=pyproject, candidates=candidates_list)


@app.command(name="analyze-benchmarks")
def analyze_benchmarks(
    benchmarks_json: Annotated[
        Path,
        typer.Option(
            "--benchmarks-json",
            help="Path to benchmarks.json file",
        ),
    ] = Path("_benchmarks/benchmarks.json"),
    output_html: Annotated[
        Path,
        typer.Option(
            "--output-html",
            help="Path to save HTML visualization",
        ),
    ] = Path("_benchmarks/benchmarks.html"),
) -> None:
    """Analyze pytest-benchmark results and visualize them.

    This command reads a benchmarks.json file produced by pytest-benchmark,
    prints a table with benchmark name, mean milliseconds, and operations per
    second, and generates an interactive Plotly bar chart of mean runtimes.

    Note: This command requires pandas and plotly. Install with:
    uv pip install -e '.[dev]' or pip install 'rhiza-tools[dev]'

    Args:
        benchmarks_json: Path to the benchmarks.json file.
        output_html: Path where the HTML visualization should be saved.

    Example:
        Analyze benchmarks with default paths::

            $ rhiza-tools analyze-benchmarks

        Use custom paths::

            $ rhiza-tools analyze-benchmarks \
                --benchmarks-json tests/benchmarks.json \
                --output-html reports/benchmarks.html
    """
    analyze_benchmarks_command(benchmarks_json=benchmarks_json, output_html=output_html)
