"""CLI commands for garbage collection and cleanup (CONC3).

Provides ``agents cleanup`` with subcommands for scanning and purging
stale sandboxes, checkpoints, sessions, logs, and backups.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, Annotated

import typer

from cleveragents.cli.main import get_console, get_err_console

if TYPE_CHECKING:
    from cleveragents.application.services.cleanup_service import (
        CleanupReport,
        CleanupService,
    )

app = typer.Typer(
    help="Garbage collection and cleanup for stale resources.",
)


def _detect_active_plan_ids(service: CleanupService) -> frozenset[str]:
    """Best-effort detection of currently active plan IDs.

    Reuses the service's cached sandbox directory listing and its
    :meth:`~CleanupService.extract_plan_id_from_sandbox` parser so
    that ``/tmp`` is only iterated once per CLI invocation.

    Sandboxes modified within the last hour are assumed to belong
    to running plans.  Falls back to an empty set with a warning
    when the temp directory cannot be read.
    """
    import time

    try:
        active: set[str] = set()
        one_hour_ago = time.time() - 3600
        for p in service._get_sandbox_dirs():
            plan_id = service.extract_plan_id_from_sandbox(p)
            if plan_id:
                try:
                    mtime = p.stat().st_mtime
                    if mtime > one_hour_ago:
                        active.add(plan_id)
                except OSError:
                    pass
        return frozenset(active)
    except OSError:
        err = get_err_console()
        err.print(
            "[yellow]Warning: Could not scan for active plans. "
            "Running plans will NOT be protected from cleanup.[/yellow]"
        )
        return frozenset()


def _get_cleanup_service() -> CleanupService:
    """Build a :class:`CleanupService` from current settings.

    Constructs the service, detects active plans from the cached
    sandbox listing, then injects the active set before returning.
    This ensures ``/tmp`` is iterated only once.
    """
    from cleveragents.application.services.cleanup_service import CleanupService
    from cleveragents.config.settings import get_settings

    settings = get_settings()
    service = CleanupService(settings=settings)
    service._active_plan_ids = _detect_active_plan_ids(service)
    return service


@app.command(name="scan")
def scan() -> None:
    """Scan for stale resources without deleting anything (dry-run)."""
    console = get_console()
    service = _get_cleanup_service()
    report = service.scan()

    console.print("\n[bold]Cleanup Scan Results (dry-run)[/bold]\n")
    _print_summary(report)

    if report.stale_items:
        console.print("\n[dim]Stale items found:[/dim]")
        for item in report.stale_items:
            console.print(
                f"  [{item.resource_type}] {item.path} ({item.age_description})"
            )
    else:
        console.print("\n[green]No stale resources found.[/green]")


@app.command(name="purge")
def purge(
    dry_run: Annotated[
        bool,
        typer.Option("--dry-run", help="Show what would be cleaned without deleting."),
    ] = False,
    purge_all: Annotated[
        bool,
        typer.Option(
            "--all",
            help=(
                "Purge all resource types "
                "(sandboxes, checkpoints, sessions, "
                "logs, backups)."
            ),
        ),
    ] = False,
    yes: Annotated[
        bool,
        typer.Option("--yes", "-y", help="Skip confirmation prompt."),
    ] = False,
) -> None:
    """Remove stale resources based on retention policies."""
    console = get_console()
    err_console = get_err_console()
    service = _get_cleanup_service()

    if dry_run:
        report = service.scan()
        console.print("\n[bold]Cleanup Dry-Run Report[/bold]\n")
        _print_summary(report)
        if report.stale_items:
            console.print("\n[dim]Would clean:[/dim]")
            for item in report.stale_items:
                console.print(f"  [{item.resource_type}] {item.path}")
        else:
            console.print("\n[green]Nothing to clean.[/green]")
        return

    if not yes:
        scope = "all resource types" if purge_all else "sandboxes and checkpoints"
        confirm = typer.confirm(f"Purge stale {scope}?")
        if not confirm:
            err_console.print("[yellow]Aborted.[/yellow]")
            raise typer.Abort()

    report = service.purge(purge_all=purge_all)

    console.print("\n[bold]Cleanup Complete[/bold]\n")
    _print_summary(report)

    if purge_all and report.sessions.removed == 0:
        console.print(
            "\n[dim]Note: Session cleanup is not yet implemented. "
            "Inactive sessions must be removed manually.[/dim]"
        )


@app.command(name="status")
def status() -> None:
    """Show current retention policy settings."""
    from cleveragents.config.settings import get_settings

    console = get_console()
    settings = get_settings()

    console.print("\n[bold]Cleanup Retention Policies[/bold]\n")
    console.print(
        f"  Sandbox max age:        {settings.cleanup_sandbox_max_age_hours} hours"
    )
    console.print(
        f"  Checkpoint max/plan:    {settings.cleanup_checkpoint_max_per_plan}"
    )
    console.print(
        f"  Session inactivity:     {settings.cleanup_session_inactivity_days} days"
    )
    console.print(
        f"  Log retention:          {settings.cleanup_log_retention_days} days"
    )
    console.print(
        f"  Backup retention:       {settings.cleanup_backup_retention_days} days"
    )
    console.print(f"  Schedule:               {settings.cleanup_schedule}")
    console.print()


def _print_summary(report: CleanupReport) -> None:
    """Print the per-resource cleanup summary table."""

    console = get_console()
    data = report.as_dict()
    mode = "Dry-run" if report.dry_run else "Purge"

    console.print(f"  [dim]Mode:[/dim] {mode}")
    for resource_type in ("sandboxes", "checkpoints", "sessions", "logs", "backups"):
        info = data[resource_type]
        removed_label = "to remove" if report.dry_run else "removed"
        console.print(
            f"  {resource_type.capitalize():15s}  "
            f"scanned={info['scanned']}  "
            f"{removed_label}={info['removed']}  "
            f"skipped={info['skipped']}"
        )
