"""Claude-related CLI commands for glreview."""

from __future__ import annotations

import json
import subprocess  # noqa: S404
import sys
from importlib.resources import files
from pathlib import Path

import click
from jinja2 import BaseLoader, Environment

from .claude import (
    build_fix_prompt,
    claude_available,
    parse_review_output,
    run_claude_interactive,
    run_claude_review,
)
from .claude_context import (
    ModuleContext,
    ProjectContext,
    get_default_context_path,
    load_context,
    save_context,
)
from .discovery import discover_modules
from .git import get_current_commit, get_gitlab_host, get_gitlab_project
from .gitlab import find_claude_review_comment, gitlab_available
from .registry import load_registry
from .review_service import ReviewService
from .review_state import ReviewStateChecker


def register_commands(main: click.Group) -> None:
    """Register Claude commands with the main CLI group."""
    main.add_command(claude_review)
    main.add_command(claude_init)
    main.add_command(claude_sync)
    main.add_command(claude_context)
    main.add_command(claude_fix)


@click.command("claude-review")
@click.argument("path")
@click.option("--post", is_flag=True, help="Post findings to GitLab issue")
@click.option(
    "--diff-only", is_flag=True, help="Only include diff in review (re-reviews)"
)
@click.option("--model", default="opus", help="Claude model to use")
@click.option("--dry-run", is_flag=True, help="Show prompt without running Claude")
@click.option("--no-context", is_flag=True, help="Skip loading project context")
@click.pass_context
def claude_review(
    ctx: click.Context,
    path: str,
    post: bool,
    diff_only: bool,
    model: str,
    dry_run: bool,
    no_context: bool,
) -> None:
    """Run AI-assisted code review using Claude."""
    config = ctx.obj["config"]
    registry = load_registry(config.registry_path)

    # Check claude is available (before service call to fail fast)
    if not dry_run and not claude_available():
        click.secho("Error: claude CLI not found.", fg="red")
        click.echo()
        click.echo("Install Claude Code from: https://claude.ai/code")
        sys.exit(1)

    # Tip about context
    if not no_context:
        context_path = get_default_context_path(config.root)
        if not context_path.exists():
            click.secho(
                "Tip: Run 'glreview claude-init' to generate project context",
                fg="bright_black",
            )

    # Progress callback for CLI output
    def on_progress(event: str, data: dict) -> None:
        if event == "context_loaded":
            click.echo(f"Using context for {data['path']}")
            if data["test_files"]:
                click.echo(f"  Including {data['test_files']} test file(s)")
        elif event == "large_file":
            click.secho(
                f"⚠ Large file: splitting into {data['chunk_count']} chunks",
                fg="yellow",
            )
            click.echo()
        elif event == "chunk_start":
            click.echo(
                f"Processing chunk {data['chunk_num']}/{data['total_chunks']} "
                f"(lines {data['start_line']}-{data['end_line']})..."
            )
        elif event == "chunk_done":
            click.echo()

    # Run review via service
    service = ReviewService(registry, config)

    if not dry_run:
        click.echo(f"Running Claude review ({model})...")

    result = service.run_claude_review(
        path=path,
        model=model,
        post=post,
        no_context=no_context,
        diff_only=diff_only,
        dry_run=dry_run,
        on_progress=on_progress,
    )

    if not result.success:
        click.secho(f"Error: {result.message}", fg="red")
        if "not in progress" in result.message:
            click.echo("Start a review first with:")
            click.echo(f"  glreview start {path}")
        sys.exit(1)

    # Handle dry-run output
    if dry_run:
        click.echo("=" * 60)
        click.echo("PROMPT (dry-run mode):")
        click.echo("=" * 60)
        click.echo(result.prompt)
        click.echo("=" * 60)
        if result.chunk_count > 1:
            click.secho(
                f"\nNote: {result.chunk_count} chunks would be processed",
                fg="bright_black",
            )
        return

    # Output results
    click.echo()
    click.echo("=" * 60)
    click.secho("CLAUDE REVIEW RESULTS", fg="cyan", bold=True)
    click.echo("=" * 60)
    click.echo(result.review_text)
    click.echo("=" * 60)

    # Report posting status
    if post:
        if result.posted:
            click.secho("✓ Posted review to GitLab issue", fg="green")
            new_label = "required" if result.required_items else "ok"
            click.secho(f"✓ Set label review::{new_label}", fg="green")
        else:
            click.secho("Warning: Could not post to GitLab issue", fg="yellow")


@click.command("claude-init")
@click.option("--model", default="opus", help="Claude model to use")
@click.option("--dry-run", is_flag=True, help="Show prompt without running Claude")
@click.option(
    "--max-samples", default=10, help="Maximum number of files to sample for analysis"
)
@click.pass_context
def claude_init(
    ctx: click.Context,
    model: str,
    dry_run: bool,
    max_samples: int,
) -> None:
    """Initialize AI-generated project context.

    This command uses Claude to analyze your project and build context
    that enhances future code reviews. The context includes:

    - Project description, conventions, and architecture
    - Test file associations for each module
    - Import relationships between modules
    - Review notes and considerations

    The context is saved to .glreview/context.json and should be
    committed to version control.
    """
    config = ctx.obj["config"]
    context_path = get_default_context_path(config.root)

    # Check if context already exists
    if context_path.exists() and not dry_run:
        click.secho("Context already exists at .glreview/context.json", fg="yellow")
        click.echo("Use 'glreview claude-sync' to update it, or delete and re-run.")
        sys.exit(1)

    # Check claude is available
    if not dry_run and not claude_available():
        click.secho("Error: claude CLI not found.", fg="red")
        click.echo()
        click.echo("Install Claude Code from: https://claude.ai/code")
        sys.exit(1)

    # Discover all modules
    modules = discover_modules(config.root, config.sources, config.exclude)
    if not modules:
        click.echo("No modules found. Run 'glreview init' first.")
        sys.exit(1)

    click.echo(f"Found {len(modules)} modules to analyze...")

    # Discover other files (tests, configs, docs)
    other_files = _discover_other_files(config, modules)

    # Sample source code from key modules
    samples = _sample_modules(config, modules, max_samples)

    # Load and render template
    template_file = files("glreview.templates").joinpath("claude_init_prompt.md")
    template_content = template_file.read_text()

    env = Environment(loader=BaseLoader(), autoescape=False)  # noqa: S701
    template = env.from_string(template_content)

    prompt = template.render(
        root=str(config.root),
        module_count=len(modules),
        module_paths=modules,
        other_files=other_files[:100],
        samples=samples,
    )

    if dry_run:
        click.echo("=" * 60)
        click.echo("PROMPT (dry-run mode):")
        click.echo("=" * 60)
        click.echo(prompt)
        click.echo("=" * 60)
        return

    # Run Claude
    click.echo(f"Running Claude analysis ({model})...")
    click.echo("This may take a minute for large projects...")
    result, success = run_claude_review(prompt, model=model)

    if not success:
        click.secho(f"Error: {result}", fg="red")
        sys.exit(1)

    # Parse and save context
    context = _parse_context_response(result)
    if context is None:
        sys.exit(1)

    current_commit = get_current_commit(cwd=config.root)
    save_context(context, context_path, commit=current_commit)

    click.echo()
    click.secho("✓ Project context generated", fg="green")
    click.echo(f"  File: {context_path}")
    click.echo(f"  Commit: {current_commit}")
    click.echo(f"  Modules analyzed: {len(context.modules)}")
    click.echo()
    click.echo("Project summary:")
    click.echo(f"  {context.description}")
    click.echo()
    click.echo("Next steps:")
    click.echo("  1. Review .glreview/context.json and edit if needed")
    click.echo("  2. Commit the context file to version control")
    click.echo("  3. Run 'glreview claude-sync' after significant changes")


def _discover_other_files(config, modules: list[str]) -> list[str]:
    """Discover non-source files (tests, configs, docs)."""
    all_py_files = list(config.root.rglob("*.py"))
    all_md_files = list(config.root.rglob("*.md"))
    all_toml_files = list(config.root.rglob("*.toml"))
    all_yaml_files = list(config.root.rglob("*.yaml")) + list(
        config.root.rglob("*.yml")
    )

    other_files = []
    for f in all_py_files + all_md_files + all_toml_files + all_yaml_files:
        try:
            rel_path = str(f.relative_to(config.root))
            if any(
                part.startswith(".")
                for part in rel_path.split("/")
                if part not in (".", "..")
            ):
                continue
            if "venv" in rel_path or "__pycache__" in rel_path:
                continue
            if rel_path not in modules:
                other_files.append(rel_path)
        except ValueError:
            continue

    other_files.sort()
    return other_files


def _sample_modules(config, modules: list[str], max_samples: int) -> list[dict]:
    """Sample source code from key modules."""
    samples: list[dict[str, str]] = []
    dirs_sampled: set[str] = set()

    for path in modules:
        if len(samples) >= max_samples:
            break
        dir_path = str(Path(path).parent)
        if dir_path in dirs_sampled and len(samples) >= max_samples // 2:
            continue
        dirs_sampled.add(dir_path)

        source_path = config.root / path
        if source_path.exists():
            content = source_path.read_text()
            if len(content) > 10000:
                content = content[:10000] + "\n\n# ... (truncated)"
            samples.append({"path": path, "content": content})

    return samples


def _parse_context_response(result: str) -> ProjectContext | None:
    """Parse Claude's JSON response into a ProjectContext."""
    import re

    try:
        json_str = result.strip()

        # Try to extract JSON from a code block (```json ... ``` or ``` ... ```)
        code_block_match = re.search(
            r"```(?:json)?\s*\n(.*?)\n```", json_str, re.DOTALL
        )
        if code_block_match:
            json_str = code_block_match.group(1)
        elif json_str.startswith("```"):
            # Fallback: handle case where response starts with ```
            lines = json_str.split("\n")
            if len(lines) > 2:
                # Remove first and last lines if properly fenced
                if lines[-1].strip() == "```":
                    json_str = "\n".join(lines[1:-1])
                else:
                    json_str = "\n".join(lines[1:])
            elif len(lines) == 2:
                json_str = lines[1] if lines[1].strip() != "```" else ""
            else:
                json_str = ""
        else:
            # Try to find raw JSON object in the response
            json_match = re.search(r"\{.*\}", json_str, re.DOTALL)
            if json_match:
                json_str = json_match.group(0)

        context_data = json.loads(json_str)
    except json.JSONDecodeError as e:
        click.secho(f"Error parsing Claude response as JSON: {e}", fg="red")
        click.echo()
        click.echo("Raw response:")
        click.echo(result)
        return None

    project_data = context_data.get("project", {})
    modules_data = context_data.get("modules", {})

    context = ProjectContext(
        description=project_data.get("description", ""),
        conventions=project_data.get("conventions", ""),
        architecture=project_data.get("architecture", ""),
        test_patterns=project_data.get("test_patterns", ""),
    )

    for path, mod_data in modules_data.items():
        context.set_module(
            ModuleContext(
                path=path,
                purpose=mod_data.get("purpose", ""),
                test_files=mod_data.get("test_files", []),
                imports_from=mod_data.get("imports_from", []),
                imported_by=mod_data.get("imported_by", []),
                related_files=mod_data.get("related_files", []),
                notes=mod_data.get("notes", ""),
            )
        )

    return context


@click.command("claude-sync")
@click.option("--model", default="opus", help="Claude model to use")
@click.option("--dry-run", is_flag=True, help="Show prompt without running Claude")
@click.option(
    "--force", "-f", is_flag=True, help="Force full rebuild instead of incremental"
)
@click.pass_context
def claude_sync(
    ctx: click.Context,
    model: str,
    dry_run: bool,
    force: bool,
) -> None:
    """Update AI-generated project context.

    This command updates the project context to reflect changes since
    the last sync. It's more efficient than claude-init as it only
    analyzes changed files.

    Use --force to do a full rebuild instead of incremental update.
    """
    config = ctx.obj["config"]
    context_path = get_default_context_path(config.root)

    # Check if context exists
    if not context_path.exists():
        if force:
            click.echo("No existing context, running full init...")
            ctx.invoke(claude_init, model=model, dry_run=dry_run)
            return
        click.secho("No context found at .glreview/context.json", fg="yellow")
        click.echo("Run 'glreview claude-init' first, or use --force to create.")
        sys.exit(1)

    # Load existing context
    context = load_context(context_path)

    if not context.generated_commit:
        click.secho(
            "Context has no commit reference, doing full rebuild...", fg="yellow"
        )
        ctx.invoke(claude_init, model=model, dry_run=dry_run)
        return

    # Check if we're up to date
    current_commit = get_current_commit(cwd=config.root)
    if context.generated_commit == current_commit and not force:
        click.secho("✓ Context is up to date", fg="green")
        click.echo(f"  Generated at: {context.generated_at}")
        click.echo(f"  Commit: {context.generated_commit}")
        return

    # Get changed files since last sync
    changes = _get_git_changes(config, context.generated_commit)
    if changes is None:
        click.echo("Running full rebuild...")
        context_path.unlink()
        ctx.invoke(claude_init, model=model, dry_run=dry_run)
        return

    changed_modules, added_modules, removed_modules = changes

    total_changes = len(changed_modules) + len(added_modules) + len(removed_modules)

    if total_changes == 0 and not force:
        click.secho("✓ No source modules changed since last sync", fg="green")
        save_context(context, context_path, commit=current_commit)
        click.echo(f"  Updated commit reference to {current_commit}")
        return

    click.echo(f"Changes since {context.generated_commit[:7]}:")
    click.echo(f"  Modified: {len(changed_modules)}")
    click.echo(f"  Added: {len(added_modules)}")
    click.echo(f"  Removed: {len(removed_modules)}")
    click.echo()

    if not dry_run and not claude_available():
        click.secho("Error: claude CLI not found.", fg="red")
        sys.exit(1)

    # Read content of changed/added files
    samples = []
    for path in changed_modules + added_modules:
        source_path = config.root / path
        if source_path.exists():
            content = source_path.read_text()
            if len(content) > 10000:
                content = content[:10000] + "\n\n# ... (truncated)"
            samples.append({"path": path, "content": content})

    # Load and render sync template
    template_file = files("glreview.templates").joinpath("claude_sync_prompt.md")
    template_content = template_file.read_text()

    env = Environment(loader=BaseLoader(), autoescape=False)  # noqa: S701
    template = env.from_string(template_content)

    prompt = template.render(
        current_context=json.dumps(context.to_dict(), indent=2),
        previous_commit=context.generated_commit,
        current_commit=current_commit,
        changed_files=changed_modules,
        added_files=added_modules,
        removed_files=removed_modules,
        samples=samples,
    )

    if dry_run:
        click.echo("=" * 60)
        click.echo("PROMPT (dry-run mode):")
        click.echo("=" * 60)
        click.echo(prompt)
        click.echo("=" * 60)
        return

    # Run Claude
    click.echo(f"Running Claude sync ({model})...")
    result, success = run_claude_review(prompt, model=model)

    if not success:
        click.secho(f"Error: {result}", fg="red")
        sys.exit(1)

    # Parse and save context
    new_context = _parse_context_response(result)
    if new_context is None:
        sys.exit(1)

    save_context(new_context, context_path, commit=current_commit)

    click.echo()
    click.secho("✓ Project context updated", fg="green")
    click.echo(f"  Commit: {current_commit}")
    click.echo(f"  Modules: {len(new_context.modules)}")


def _get_git_changes(
    config, since_commit: str
) -> tuple[list[str], list[str], list[str]] | None:
    """Get changed, added, and removed files since a commit."""
    try:
        git_result = subprocess.run(  # noqa: S607
            ["git", "diff", "--name-status", since_commit, "HEAD"],
            cwd=config.root,
            capture_output=True,
            text=True,
        )
        if git_result.returncode != 0:
            click.secho(f"Could not get git diff from {since_commit}", fg="yellow")
            return None
    except OSError:
        click.secho("Git not available", fg="red")
        sys.exit(1)

    changed_files = []
    added_files = []
    removed_files = []

    for line in git_result.stdout.strip().split("\n"):
        if not line:
            continue
        parts = line.split("\t")
        if len(parts) >= 2:
            status, path = parts[0], parts[-1]
            if status.startswith("M"):
                changed_files.append(path)
            elif status.startswith("A"):
                added_files.append(path)
            elif status.startswith("D"):
                removed_files.append(path)
            elif status.startswith("R"):
                if len(parts) >= 3:
                    removed_files.append(parts[1])
                    added_files.append(parts[2])

    # Filter to only source modules
    modules = set(discover_modules(config.root, config.sources, config.exclude))
    context = load_context(get_default_context_path(config.root))

    changed_modules = [f for f in changed_files if f in modules]
    added_modules = [f for f in added_files if f in modules]
    removed_modules = [f for f in removed_files if f in context.modules]

    return changed_modules, added_modules, removed_modules


@click.command("claude-context")
@click.argument("path", required=False)
@click.pass_context
def claude_context(ctx: click.Context, path: str | None) -> None:
    """Show AI-generated context for a module or project.

    If PATH is provided, shows context for that specific module.
    Otherwise, shows project-level context.
    """
    config = ctx.obj["config"]
    context_path = get_default_context_path(config.root)

    if not context_path.exists():
        click.secho("No context found at .glreview/context.json", fg="yellow")
        click.echo("Run 'glreview claude-init' to generate context.")
        sys.exit(1)

    context = load_context(context_path)

    if path:
        _show_module_context(context, path)
    else:
        _show_project_context(context)


def _show_module_context(context: ProjectContext, path: str) -> None:
    """Display context for a specific module."""
    module_ctx = context.get_module(path)
    if not module_ctx:
        click.secho(f"No context found for {path}", fg="yellow")
        click.echo()
        click.echo("Available modules:")
        for mod_path in sorted(context.modules.keys())[:10]:
            click.echo(f"  {mod_path}")
        if len(context.modules) > 10:
            click.echo(f"  ... and {len(context.modules) - 10} more")
        sys.exit(1)

    click.secho(f"Context for {path}", fg="cyan", bold=True)
    click.echo()
    click.echo(f"Purpose: {module_ctx.purpose}")
    click.echo()

    if module_ctx.test_files:
        click.echo("Test files:")
        for t in module_ctx.test_files:
            click.echo(f"  - {t}")
        click.echo()

    if module_ctx.imports_from:
        click.echo("Imports from:")
        for i in module_ctx.imports_from:
            click.echo(f"  - {i}")
        click.echo()

    if module_ctx.imported_by:
        click.echo("Imported by:")
        for i in module_ctx.imported_by:
            click.echo(f"  - {i}")
        click.echo()

    if module_ctx.related_files:
        click.echo("Related files:")
        for r in module_ctx.related_files:
            click.echo(f"  - {r}")
        click.echo()

    if module_ctx.notes:
        click.echo(f"Notes: {module_ctx.notes}")


def _show_project_context(context: ProjectContext) -> None:
    """Display project-level context."""
    click.secho("Project Context", fg="cyan", bold=True)
    click.echo()
    click.echo(f"Generated: {context.generated_at}")
    click.echo(f"Commit: {context.generated_commit}")
    click.echo(f"Modules: {len(context.modules)}")
    click.echo()

    if context.description:
        click.secho("Description:", bold=True)
        click.echo(f"  {context.description}")
        click.echo()

    if context.conventions:
        click.secho("Conventions:", bold=True)
        for line in context.conventions.split("\n"):
            click.echo(f"  {line}")
        click.echo()

    if context.architecture:
        click.secho("Architecture:", bold=True)
        for line in context.architecture.split("\n"):
            click.echo(f"  {line}")
        click.echo()

    if context.test_patterns:
        click.secho("Test Patterns:", bold=True)
        click.echo(f"  {context.test_patterns}")


@click.command("claude-fix")
@click.argument("path")
@click.option("--batch", is_flag=True, help="Non-interactive (REQUIRED only)")
@click.option("--model", default="opus", help="Claude model to use")
@click.option("--dry-run", is_flag=True, help="Show prompt without running Claude")
@click.option(
    "--review", "review_file", type=click.Path(exists=True), help="Use review from file"
)
@click.option("--no-context", is_flag=True, help="Skip loading project context")
@click.pass_context
def claude_fix(
    ctx: click.Context,
    path: str,
    batch: bool,
    model: str,
    dry_run: bool,
    review_file: str | None,
    no_context: bool,
) -> None:
    """Fix issues identified in a Claude review.

    In interactive mode (default), displays all findings and lets you select
    which items to fix. REQUIRED items are pre-selected.

    In batch mode (--batch), automatically fixes all REQUIRED items without
    prompting.

    The review findings are fetched from the GitLab issue comments.
    Use --review to provide a review file instead.
    """
    config = ctx.obj["config"]
    registry = load_registry(config.registry_path)

    module = registry.get(path)
    if not module:
        click.echo(f"Error: {path} not in registry.")
        sys.exit(1)

    if module.status != "in_progress":
        click.echo(f"Error: {path} is not in progress (status: {module.status})")
        click.echo("Start a review first with:")
        click.echo(f"  glreview start {path}")
        sys.exit(1)

    # Check claude is available
    if not dry_run and not claude_available():
        click.secho("Error: claude CLI not found.", fg="red")
        click.echo()
        click.echo("Install Claude Code from: https://claude.ai/code")
        sys.exit(1)

    # Get review findings
    review_text = _get_review_text(config, module, review_file)
    if review_text is None:
        sys.exit(1)

    # Parse review
    parsed = parse_review_output(review_text)

    if not parsed.required_items and not parsed.suggested_items:
        click.secho("✓ No issues to fix!", fg="green")
        sys.exit(0)

    # Select items to fix
    if batch:
        # Batch mode: fix REQUIRED items only
        if not parsed.required_items:
            click.secho("✓ No REQUIRED items to fix.", fg="green")
            if parsed.suggested_items:
                click.echo(f"  ({len(parsed.suggested_items)} SUGGESTED items skipped)")
            sys.exit(0)
        selected_items = parsed.required_items
        click.echo(f"Batch mode: fixing {len(selected_items)} REQUIRED items")
    else:
        # Interactive mode: let user select items
        selected_items = _select_items_to_fix(parsed)
        if not selected_items:
            click.echo("No items selected. Exiting.")
            sys.exit(0)

    # Load project context if available
    project_ctx = None
    module_ctx = None
    if not no_context:
        context_path = get_default_context_path(config.root)
        if context_path.exists():
            project_ctx = load_context(context_path)
            module_ctx = project_ctx.get_module(path)

    # Read source file
    source_path = config.root / path
    if not source_path.exists():
        click.echo(f"Error: File not found: {source_path}")
        sys.exit(1)

    source_code = source_path.read_text()

    # Separate selected items by type for the prompt
    selected_required = [i for i in selected_items if i.rating == "REQUIRED"]
    selected_suggested = [i for i in selected_items if i.rating == "SUGGESTED"]

    # Build fix prompt
    prompt = build_fix_prompt(
        path=path,
        source_code=source_code,
        module_status=module,
        config=config,
        required_items=selected_required,
        suggested_items=selected_suggested if selected_suggested else None,
        project_context=project_ctx,
        module_context=module_ctx,
        fix_all=bool(selected_suggested),
    )

    if dry_run:
        click.echo("=" * 60)
        click.echo("PROMPT (dry-run mode):")
        click.echo("=" * 60)
        click.echo(prompt)
        click.echo("=" * 60)
        return

    if batch:
        _run_batch_fix(prompt, model)
    else:
        _run_interactive_fix(prompt, model)

    click.echo()
    click.secho("Fix session complete.", fg="green")
    click.echo()
    click.echo("Next steps:")
    click.echo("  1. Review changes: git diff")
    click.echo("  2. Run tests to verify fixes")
    click.echo("  3. Commit if satisfied: git add -p && git commit")


def _get_review_text(config, module, review_file: str | None) -> str | None:
    """Get review text from file or GitLab issue."""
    if review_file:
        review_text = Path(review_file).read_text()
        click.echo(f"Loaded review from {review_file}")
        return review_text

    # Fetch from GitLab issue
    issue_number = ReviewStateChecker.extract_issue_number(module.review_issue)
    if not issue_number:
        click.secho("Error: No issue found for this module.", fg="red")
        click.echo("Use --review FILE to provide review findings manually.")
        return None

    project = get_gitlab_project(cwd=config.root)
    host = get_gitlab_host(cwd=config.root)

    if not gitlab_available(host):
        click.secho("Error: GitLab not available.", fg="red")
        click.echo("Use --review FILE to provide review findings manually.")
        return None

    click.echo(f"Fetching review from issue #{issue_number}...")
    fetched_review = find_claude_review_comment(issue_number, project, host)

    if not fetched_review:
        click.secho("No Claude review found in issue comments.", fg="yellow")
        click.echo()
        click.echo("Options:")
        click.echo(f"  1. Run 'glreview claude-review {module.path} --post' first")
        click.echo("  2. Use --review FILE to provide review findings")
        return None

    return fetched_review


def _display_fix_summary(parsed, fix_all: bool) -> None:
    """Display summary of items to fix."""
    click.echo()
    click.echo(f"Found {len(parsed.required_items)} REQUIRED items")
    if parsed.suggested_items:
        click.echo(f"Found {len(parsed.suggested_items)} SUGGESTED items")
    click.echo()

    if parsed.required_items:
        click.secho("REQUIRED fixes:", fg="red", bold=True)
        for item in parsed.required_items:
            click.echo(f"  - {item.criterion}: {item.description[:80]}...")
        click.echo()

    if fix_all and parsed.suggested_items:
        click.secho("SUGGESTED fixes:", fg="yellow", bold=True)
        for item in parsed.suggested_items:
            click.echo(f"  - {item.criterion}: {item.description[:80]}...")
        click.echo()


def _select_items_to_fix(parsed) -> list:
    """Interactively select items to fix.

    Displays all REQUIRED and SUGGESTED items and lets the user select
    which ones to fix. REQUIRED items are pre-selected by default.

    Args:
        parsed: ParsedReview object with required_items and suggested_items.

    Returns:
        List of selected ReviewItem objects.
    """
    from .claude import ReviewItem

    all_items: list[tuple[int, ReviewItem, bool]] = []  # (index, item, pre_selected)

    # Add REQUIRED items (pre-selected)
    for item in parsed.required_items:
        all_items.append((len(all_items) + 1, item, True))

    # Add SUGGESTED items (not pre-selected)
    for item in parsed.suggested_items:
        all_items.append((len(all_items) + 1, item, False))

    if not all_items:
        return []

    # Display items
    click.echo()
    if parsed.required_items:
        click.secho("REQUIRED:", fg="red", bold=True)
        for idx, item, _ in all_items:
            if item.rating == "REQUIRED":
                desc = item.description[:60]
                if len(item.description) > 60:
                    desc += "..."
                click.echo(f"  [{idx}] ✓ {item.criterion}: {desc}")

    if parsed.suggested_items:
        click.echo()
        click.secho("SUGGESTED:", fg="yellow", bold=True)
        for idx, item, _ in all_items:
            if item.rating == "SUGGESTED":
                desc = item.description[:60]
                if len(item.description) > 60:
                    desc += "..."
                click.echo(f"  [{idx}]   {item.criterion}: {desc}")

    click.echo()

    # Build default selection (all REQUIRED items)
    default_selection = [str(idx) for idx, item, pre in all_items if pre]
    default_str = ",".join(default_selection) if default_selection else ""

    # Prompt for selection
    click.echo("Enter items to fix (e.g., 1,2,3 or 1-3 or 'all')")
    selection = click.prompt(
        "Selection",
        default=default_str,
        show_default=True,
    )

    # Parse selection
    selected_indices: set[int] = set()
    selection = selection.strip().lower()

    if selection == "all":
        selected_indices = {idx for idx, _, _ in all_items}
    elif selection == "" or selection == "none":
        return []
    else:
        # Parse comma-separated values and ranges
        for part in selection.split(","):
            part = part.strip()
            if "-" in part:
                # Range like "1-3"
                try:
                    start, end = part.split("-", 1)
                    for i in range(int(start), int(end) + 1):
                        selected_indices.add(i)
                except ValueError:
                    click.secho(f"Invalid range: {part}", fg="yellow")
            else:
                # Single number
                try:
                    selected_indices.add(int(part))
                except ValueError:
                    click.secho(f"Invalid number: {part}", fg="yellow")

    # Collect selected items
    selected_items = []
    for idx, item, _ in all_items:
        if idx in selected_indices:
            selected_items.append(item)

    if selected_items:
        click.echo()
        click.echo(f"Selected {len(selected_items)} item(s) to fix")

    return selected_items


def _run_batch_fix(prompt: str, model: str) -> None:
    """Run fix in non-interactive batch mode."""
    click.echo(f"Running Claude fix ({model}) in batch mode...")
    result, success = run_claude_review(prompt, model=model)

    if not success:
        click.secho(f"Error: {result}", fg="red")
        sys.exit(1)

    click.echo()
    click.echo("=" * 60)
    click.secho("CLAUDE FIX RESULTS", fg="cyan", bold=True)
    click.echo("=" * 60)
    click.echo(result)
    click.echo("=" * 60)


def _run_interactive_fix(prompt: str, model: str) -> None:
    """Run fix in interactive mode."""
    click.echo(f"Starting interactive Claude session ({model})...")
    click.echo()
    click.secho("You can guide Claude as it makes fixes.", fg="bright_black")
    click.secho("Type 'exit' or Ctrl+C when done.", fg="bright_black")
    click.echo()

    success = run_claude_interactive(prompt, model=model)

    if not success:
        click.secho("Claude session ended with errors.", fg="yellow")
        sys.exit(1)
