"""Label CLI commands - manage source labels in a notebook."""

import typer
from rich.table import Table

from notebooklm_tools.cli.formatters import print_json
from notebooklm_tools.cli.utils import get_client, handle_error, make_console
from notebooklm_tools.core.alias import get_alias_manager
from notebooklm_tools.core.exceptions import NLMError
from notebooklm_tools.services import ServiceError
from notebooklm_tools.services import labels as labels_service

console = make_console()
app = typer.Typer(
    help="Manage source labels in a notebook",
    rich_markup_mode="rich",
    no_args_is_help=True,
)


def _print_labels_table(labels: list[dict], notebook_id: str) -> None:
    if not labels:
        console.print(f"[dim]No labels found in notebook {notebook_id}[/dim]")
        return
    table = Table(title=f"Labels in Notebook {notebook_id}")
    table.add_column("Emoji", style="yellow", width=6)
    table.add_column("Name", style="green")
    table.add_column("Label ID", style="cyan", no_wrap=True)
    table.add_column("Sources", style="white", justify="right")
    for lbl in labels:
        table.add_row(
            lbl.get("emoji") or "",
            lbl.get("name", ""),
            lbl.get("id", "")[:8] + "...",
            str(len(lbl.get("source_ids", []))),
        )
    console.print(table)
    console.print(f"\n[dim]Total: {len(labels)} label(s)[/dim]")


@app.command("auto")
def auto_label(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Auto-label sources using AI-generated thematic categories.

    Requires 5+ sources. If labels already exist, returns current labels.
    """
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.auto_label(client, notebook_id)

        if json_output:
            print_json(result)
        else:
            _print_labels_table(result["labels"], notebook_id)

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("list")
def list_labels(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    quiet: bool = typer.Option(False, "--quiet", "-q", help="Output label IDs only"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """List current labels in a notebook.

    Note: If no labels exist, this will trigger AI auto-labeling.
    """
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.list_labels(client, notebook_id)

        labels = result["labels"]

        if quiet:
            for lbl in labels:
                console.print(lbl["id"])
        elif json_output:
            print_json(result)
        else:
            _print_labels_table(labels, notebook_id)

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("reorganize")
def reorganize_labels(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    unlabeled_only: bool = typer.Option(
        False, "--unlabeled", "-u", help="Only label sources not yet in any label"
    ),
    confirm: bool = typer.Option(
        False, "--confirm", "-y", help="Skip confirmation prompt (all-sources mode)"
    ),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Force AI re-categorization of sources into new labels.

    By default, replaces ALL existing labels (destructive). Use --unlabeled to
    only label sources that are not yet in any label.
    """
    if not unlabeled_only and not confirm:
        confirmed = typer.confirm(
            "Reorganize all sources? This will NOT preserve existing labels.",
            default=False,
        )
        if not confirmed:
            console.print("[yellow]Cancelled.[/yellow]")
            raise typer.Exit(0)

    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.reorganize_labels(client, notebook_id, unlabeled_only)

        if json_output:
            print_json({"status": "success", **result})
        else:
            scope = "unlabeled sources" if unlabeled_only else "all sources"
            console.print(f"[green]✓[/green] Reorganized {scope}.")
            _print_labels_table(result["labels"], notebook_id)

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("create")
def create_label(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    name: str = typer.Argument(..., help="Label display name"),
    emoji: str = typer.Option("", "--emoji", "-e", help="Optional emoji marker (e.g. 📊)"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Create a new empty label manually."""
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.create_label(client, notebook_id, name, emoji)

        if json_output:
            print_json({"status": "success", **result})
        else:
            console.print(f"[green]✓[/green] {result['message']}")
            if result.get("label_id"):
                console.print(f"  Label ID: {result['label_id']}")

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("rename")
def rename_label(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    label_id: str = typer.Argument(..., help="Label UUID to rename"),
    new_name: str = typer.Argument(..., help="New display name"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Rename an existing label."""
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.rename_label(client, notebook_id, label_id, new_name)

        if json_output:
            print_json({"status": "success", **result})
        else:
            console.print(f"[green]✓[/green] {result['message']}")

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("emoji")
def set_emoji(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    label_id: str = typer.Argument(..., help="Label UUID"),
    emoji: str = typer.Argument(..., help='Emoji character (use "" to clear)'),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Set or clear the emoji marker on a label."""
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.set_label_emoji(client, notebook_id, label_id, emoji)

        if json_output:
            print_json({"status": "success", **result})
        else:
            console.print(f"[green]✓[/green] {result['message']}")

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("move")
def move_source(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    source_id: str = typer.Argument(..., help="Source UUID to assign"),
    label_id: str = typer.Argument(..., help="Target label UUID"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Assign a source to a label.

    Sources support multi-label assignment — this adds the source to the
    target label without removing it from other labels.
    """
    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.move_source_to_label(client, notebook_id, label_id, source_id)

        if json_output:
            print_json({"status": "success", **result})
        else:
            console.print(f"[green]✓[/green] {result['message']}")

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))


@app.command("delete")
def delete_label(
    notebook_id: str = typer.Argument(..., help="Notebook ID or alias"),
    label_id: str = typer.Argument(..., help="Label UUID to delete"),
    confirm: bool = typer.Option(False, "--confirm", "-y", help="Confirm deletion without prompt"),
    json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
    profile: str | None = typer.Option(None, "--profile", "-p", help="Profile to use"),
) -> None:
    """Delete a label permanently. Sources are NOT deleted."""
    if not confirm:
        confirmed = typer.confirm(
            f"Delete label {label_id[:8]}...? Sources will be preserved.",
            default=False,
        )
        if not confirmed:
            console.print("[yellow]Cancelled.[/yellow]")
            raise typer.Exit(0)

    try:
        notebook_id = get_alias_manager().resolve(notebook_id)
        with get_client(profile) as client:
            result = labels_service.delete_labels(client, notebook_id, [label_id])

        if json_output:
            print_json({"status": "success", **result})
        else:
            console.print(f"[green]✓[/green] {result['message']}")

    except (ServiceError, NLMError) as e:
        handle_error(e, json_output=locals().get("json_output", False))
