"""Knowledge document ingest command implementation."""

from pathlib import Path
from typing import Annotated, Optional

import typer

from cli.commands.flag_utils import (
    require_one_of,
    validate_document_type,
    validate_source_type,
)
from cli.commands.knowledge.documents.ingest.presenter import present_ingest_success
from cli.infrastructure.command import async_command, authenticated_client
from cli.infrastructure.file_content import FileContentError, resolve_content
from cli.infrastructure.kv_parser import parse_kv_pairs
from alloy_runtime_types.dtos.knowledge import IngestDocumentRequest


def knowledge_documents_ingest_command(
    collection: str = typer.Option(
        ...,
        "-C",
        "--collection",
        help="Target collection name or UUID",
    ),
    title: str = typer.Option(
        ...,
        "-t",
        "--title",
        help="Document title",
    ),
    file: Optional[Path] = typer.Option(
        None,
        "-f",
        "--file",
        help="Path to document file",
        exists=True,
        readable=True,
    ),
    content: Optional[str] = typer.Option(
        None,
        "-c",
        "--content",
        help="Document content (or @file, or @- for stdin)",
    ),
    question_agent: Optional[str] = typer.Option(
        None,
        "-Q",
        "--question-agent",
        help="Agent name or UUID for question generation (required unless --skip-question-gen)",
    ),
    question_template: Optional[str] = typer.Option(
        None,
        "-T",
        "--question-template",
        help="Template name or UUID for question generation (required unless --skip-question-gen)",
    ),
    source_type: str = typer.Option(
        "upload",
        "-s",
        "--source-type",
        help="Source type: upload, paste, api_import, url_scrape",
    ),
    metadata: Annotated[
        Optional[list[str]],
        typer.Option(
            "-m",
            "--metadata",
            help="Metadata (key=value or key:=json). Repeatable.",
        ),
    ] = None,
    tag: Annotated[
        Optional[list[str]],
        typer.Option(
            "--tag",
            help="Hierarchical tag path (e.g., 'engineering.backend'). Repeatable.",
        ),
    ] = None,
    document_type: str = typer.Option(
        "document",
        "-D",
        "--document-type",
        help="Document type for preprocessing: transcript, markdown, document, form",
    ),
    external_id: Optional[str] = typer.Option(
        None,
        "-e",
        "--external-id",
        help="Caller-provided ID for idempotency and correlation (unique per org)",
    ),
    dry_run: bool = typer.Option(
        False,
        "--dry-run",
        help="Only preprocess - don't persist. Useful for testing preprocessing.",
    ),
    skip_question_gen: bool = typer.Option(
        False,
        "--skip-question-gen",
        help="Skip question generation during ingestion. Makes -Q and -T optional.",
    ),
) -> None:
    """Ingest a document into a knowledge collection.

    Document content can be provided via:
    - --file: Read from a file path
    - --content: Direct text, @file reference, or @- for stdin

    Document types control preprocessing:
    - transcript: Podcasts/videos/meetings with timestamps and natural speech
    - markdown: Markdown-formatted content
    - document: General text documents (default)
    - form: Semi-structured forms, applications, surveys, and intake exports

    Examples:
        alloy knowledge documents ingest -C <uuid> -t "API Docs" -f ./api.md -Q <agent> -T <template>
        alloy knowledge documents ingest -C <uuid> -t "Notes" -c "My content" -Q <agent> -T <template>
        cat doc.txt | alloy knowledge documents ingest -C <uuid> -t "Doc" -c @- -Q <agent> -T <template>
        alloy knowledge documents ingest -C <uuid> -t "Doc" -c @notes.md -Q <agent> -T <template> -m author=John
        alloy knowledge documents ingest -C <uuid> -t "Meeting" -f meeting.vtt -D transcript -Q <agent> -T <template>
        alloy knowledge documents ingest -C <uuid> -t "Test" -f doc.md --dry-run -Q <agent> -T <template>
    """
    require_one_of(("--file", file), ("--content", content))

    _execute_ingest_from_flags(
        collection=collection,
        title=title,
        file=file,
        content=content,
        question_agent=question_agent,
        question_template=question_template,
        source_type=source_type,
        metadata=metadata,
        tag=tag,
        document_type=document_type,
        external_id=external_id,
        dry_run=dry_run,
        skip_question_gen=skip_question_gen,
    )


def _execute_ingest_from_flags(
    collection: str,
    title: str,
    file: Optional[Path],
    content: Optional[str],
    question_agent: Optional[str],
    question_template: Optional[str],
    source_type: str,
    metadata: Optional[list[str]],
    tag: Optional[list[str]],
    document_type: str,
    external_id: Optional[str],
    dry_run: bool,
    skip_question_gen: bool,
) -> None:
    """Build and execute document ingestion from command flags."""
    # Validate source type
    validated_source_type = validate_source_type(source_type)

    # Validate document type
    validated_document_type = validate_document_type(document_type)

    # Resolve content from file or inline
    if file:
        if not file.is_file():
            raise typer.BadParameter(f"Not a file: {file}")
        try:
            document_content = file.read_text(encoding="utf-8")
        except UnicodeDecodeError:
            raise typer.BadParameter(
                f"File is not valid UTF-8 text: {file}. Only text files are supported."
            )
    else:
        try:
            document_content = resolve_content(content) or ""
        except FileContentError as e:
            raise typer.BadParameter(str(e))

    if not document_content.strip():
        raise typer.BadParameter("Document content cannot be empty")

    # Validate question generation requirements
    if not skip_question_gen:
        if question_agent is None:
            raise typer.BadParameter(
                "--question-agent (-Q) is required unless --skip-question-gen is set"
            )
        if question_template is None:
            raise typer.BadParameter(
                "--question-template (-T) is required unless --skip-question-gen is set"
            )

    # Parse metadata (httpie style)
    parsed_metadata = parse_kv_pairs(metadata) if metadata else None

    request = IngestDocumentRequest(
        collection_id=collection,
        title=title,
        content=document_content,
        question_gen_agent_id=question_agent,
        question_gen_template_id=question_template,
        source_type=validated_source_type,
        document_type=validated_document_type,  # type: ignore[arg-type]
        metadata=parsed_metadata,
        tags=tag,
        external_id=external_id,
        dry_run=dry_run,
        skip_question_generation=skip_question_gen,
    )

    _execute_ingest(request)


@async_command
async def _execute_ingest(request: IngestDocumentRequest) -> None:
    """Execute the document ingestion with the given request."""
    async with authenticated_client() as (_config, client):
        response = await client.ingest_document(request)

    present_ingest_success(response)
