"""CI command for glreview — validate review coverage in pipelines."""

from __future__ import annotations

import sys

import click

from .cli_reports import _generate_markdown_report
from .discovery import sync_registry
from .git import count_lines, get_current_commit
from .registry import ModuleStatus, load_registry, save_registry
from .review_service import ReviewService
from .state_machine import Status


def register_commands(main: click.Group) -> None:
    """Register CI commands with the main CLI group."""
    main.add_command(ci)


@click.command()
@click.option(
    "--report", "report_path", type=click.Path(), help="Write markdown report to file"
)
@click.option(
    "--fail-under",
    type=float,
    default=None,
    help="Exit 1 if review coverage is below this percentage",
)
@click.pass_context
def ci(ctx: click.Context, report_path: str | None, fail_under: float | None) -> None:
    """Run review sync and coverage check for CI.

    Syncs the registry with the filesystem, computes review coverage,
    and optionally writes a markdown report. Use --fail-under to enforce
    a minimum coverage threshold.

    Expects the .glreview/ registry to be committed in the repo.
    """
    config = ctx.obj["config"]

    # Load registry
    if not config.registry_path.exists():
        click.secho("Error: No registry found. Run 'glreview init' first.", fg="red")
        sys.exit(1)

    registry = load_registry(config.registry_path)

    # Sync: detect new/removed modules
    added, removed = sync_registry(
        config.root,
        config.sources,
        config.exclude,
        registry.modules,
    )

    if added or removed:
        click.secho("Warning: Registry is out of sync with filesystem.", fg="yellow")
        for path in added:
            lines = count_lines(path, cwd=config.root)
            registry.set(
                ModuleStatus(
                    path=path,
                    status=Status.NEEDS_REVIEW.value,
                    lines=lines,
                )
            )
            click.echo(f"  + {path}")
        for path in removed:
            registry.remove(path)
            click.echo(f"  - {path}")

        commit = get_current_commit(cwd=config.root)
        save_registry(registry, config.registry_path, commit=commit)
        click.echo("Run 'glreview sync' locally and commit the result.")
        click.echo()

    # Compute coverage
    service = ReviewService(registry, config)
    summary = service.get_summary()
    state = service.get_registry_state()
    coverage_pct = summary["coverage_pct"]
    total = summary["total"]
    reviewed = summary["reviewed"]

    click.echo(f"Review coverage: {coverage_pct:.0f}% ({reviewed}/{total} modules)")

    # Write report if requested
    if report_path:
        report_text = _generate_markdown_report(
            summary,
            state,
            coverage_pct,
            summary["line_coverage_pct"],
            reviewed,
            summary["in_progress"],
            summary["needs_review"],
            summary["total_lines"],
            summary["reviewed_lines"],
        )
        from pathlib import Path

        Path(report_path).write_text(report_text)
        click.echo(f"Report written to {report_path}")

    # Collect failures (report all before exiting)
    failed = False

    # Stale check
    if state.reviewed_stale:
        click.secho(
            f"FAIL: {len(state.reviewed_stale)} reviewed module(s) have changed:",
            fg="red",
        )
        for info in state.reviewed_stale:
            mod = info.module
            click.echo(f"  {mod.path} (reviewed at {mod.last_reviewed_commit})")
        failed = True

    # Coverage gate
    if fail_under is not None and coverage_pct < fail_under:
        click.secho(
            f"FAIL: Review coverage {coverage_pct:.0f}% < {fail_under:.0f}%",
            fg="red",
        )
        failed = True

    if failed:
        sys.exit(1)
