"""Document CLI commands.

Commands for viewing crawled documents and their chunks.
"""

from functools import partial
from typing import Annotated, Any

import typer

from sibyl_cli.client import SibylClientError, get_client
from sibyl_cli.common import (
    ELECTRIC_PURPLE,
    NEON_CYAN,
    console,
    handle_client_error,
    info,
    run_async,
    truncate,
)
from sibyl_cli.view_shared import maybe_print_json, render_detail_panel, render_table_or_empty

app = typer.Typer(
    name="documents",
    help="Browse crawled documents",
    no_args_is_help=True,
)

_handle_client_error = partial(handle_client_error, not_found_label="Document not found")


@app.command("show")
def show_document(
    document_id: Annotated[str, typer.Argument(help="Document ID (from search results metadata)")],
    raw: Annotated[bool, typer.Option("--raw", "-r", help="Show raw markdown content")] = False,
    json_out: Annotated[
        bool, typer.Option("--json", "-j", help="JSON output (for scripting)")
    ] = False,
) -> None:
    """Show full document content.

    Use the document_id from search result metadata to fetch the complete document.

    Example:
        sibyl search "proto config"
        # Note the document_id in metadata
        sibyl crawl documents show 22d4cf79-8561-4be0-8067-da8673e3439d
    """

    @run_async
    async def _show() -> None:
        client = get_client()

        try:
            doc = await client.get_crawl_document(document_id)

            if maybe_print_json(doc, json_out=json_out):
                return

            if raw:
                # Just print raw content
                content = doc.get("raw_content") or doc.get("content", "")
                console.print(content)
                return

            # Rich formatted output
            title = doc.get("title", "Untitled")
            url = doc.get("url", "")
            source_name = doc.get("source_name", "")
            # Prefer markdown_content (assembled from chunks) over raw_content (HTML)
            content = doc.get("markdown_content") or doc.get("raw_content") or ""
            chunks = doc.get("chunks", [])

            lines = [
                f"[{ELECTRIC_PURPLE}]Title:[/{ELECTRIC_PURPLE}] {title}",
                f"[{ELECTRIC_PURPLE}]ID:[/{ELECTRIC_PURPLE}] {document_id}",
            ]

            if url:
                lines.append(f"[{ELECTRIC_PURPLE}]URL:[/{ELECTRIC_PURPLE}] {url}")
            if source_name:
                lines.append(f"[{ELECTRIC_PURPLE}]Source:[/{ELECTRIC_PURPLE}] {source_name}")

            lines.append(f"[{ELECTRIC_PURPLE}]Chunks:[/{ELECTRIC_PURPLE}] {len(chunks)}")
            lines.append("")

            if content:
                lines.append(f"[{NEON_CYAN}]Content:[/{NEON_CYAN}]")
                lines.append("")
                # Show content with reasonable limit
                if len(content) > 5000:
                    lines.append(content[:5000])
                    lines.append("")
                    lines.append(
                        f"[dim]... truncated ({len(content)} chars total, use --raw for full)[/dim]"
                    )
                else:
                    lines.append(content)
            else:
                lines.append("[dim]No content available[/dim]")

            render_detail_panel(
                title="Document",
                lines=lines,
                footer=(
                    f"\n[dim]Open in browser:[/dim] [{NEON_CYAN}]{url}[/{NEON_CYAN}]"
                    if url
                    else None
                ),
            )

        except SibylClientError as e:
            _handle_client_error(e)

    _show()


@app.command("list")
def list_documents(
    source_id: Annotated[
        str | None, typer.Option("--source", "-s", help="Filter by source ID")
    ] = None,
    limit: Annotated[int, typer.Option("--limit", "-n", help="Max results")] = 20,
    json_out: Annotated[
        bool, typer.Option("--json", "-j", help="JSON output (for scripting)")
    ] = False,
) -> None:
    """List crawled documents."""

    @run_async
    async def _list() -> None:
        client = get_client()

        try:
            response = await client.list_crawl_documents(source_id=source_id, limit=limit)
            docs: list[dict[str, Any]] = response.get("documents", [])

            if maybe_print_json(docs, json_out=json_out):
                return

            rows = [
                (
                    truncate(doc.get("id", ""), 36),
                    truncate(doc.get("title", ""), 30),
                    truncate(doc.get("url", ""), 40),
                    str(len(doc.get("chunks", []))),
                )
                for doc in docs
            ]
            render_table_or_empty(
                title="Documents",
                columns=("ID", "Title", "URL", "Chunks"),
                rows=rows,
                empty_message="No documents found",
                empty_printer=info,
                footer=f"\n[dim]Showing {len(docs)} document(s)[/dim]" if docs else None,
            )

        except SibylClientError as e:
            _handle_client_error(e)

    _list()
