"""Knowledge documents update metadata command implementation."""

import json
from typing import Any, cast

import typer

from cli.commands.knowledge.documents.update.presenter import (
    present_update_metadata_result,
)
from cli.infrastructure.command import async_command, authenticated_client
from cli.infrastructure.file_content import resolve_content_or_raise
from alloy_runtime_types.dtos.knowledge import UpdateDocumentMetadataRequest


def knowledge_documents_update_command(
    document_id: str = typer.Argument(
        ...,
        help="Document UUID",
    ),
    metadata: str = typer.Option(
        ...,
        "--metadata",
        help="Metadata JSON object (or @file.json)",
    ),
    metadata_mode: str = typer.Option(
        "merge",
        "--metadata-mode",
        help="Metadata update mode: 'merge' (default) or 'replace'",
    ),
) -> None:
    """Update a document's metadata.

    The --metadata flag accepts a JSON string or @file reference.
    Use --metadata-mode to control whether keys are merged with
    existing metadata (default) or replace it entirely.

    Examples:
        alloy knowledge documents update <uuid> --metadata '{"key": "value"}'
        alloy knowledge documents update <uuid> --metadata @meta.json --metadata-mode replace
    """
    _execute_update(
        document_id=document_id,
        metadata_raw=metadata,
        metadata_mode=metadata_mode,
    )


@async_command
async def _execute_update(
    document_id: str,
    metadata_raw: str,
    metadata_mode: str,
) -> None:
    """Execute document metadata update operation."""

    if metadata_mode not in ("merge", "replace"):
        raise typer.BadParameter(
            f"Invalid metadata mode '{metadata_mode}'. Must be 'merge' or 'replace'."
        )

    resolved = resolve_content_or_raise(metadata_raw)
    if resolved is None:
        raise typer.BadParameter("--metadata is required")

    try:
        parsed = json.loads(resolved)
    except json.JSONDecodeError as e:
        raise typer.BadParameter(f"Invalid JSON for --metadata: {e}")
    if not isinstance(parsed, dict):
        raise typer.BadParameter("--metadata must be a JSON object")
    metadata_dict = cast(dict[str, Any], parsed)

    request = UpdateDocumentMetadataRequest(
        metadata=metadata_dict,
        metadata_mode=metadata_mode,  # type: ignore[arg-type]
    )

    async with authenticated_client() as (_config, client):
        response = await client.update_document_metadata(
            document_id=document_id,
            request=request,
        )

    present_update_metadata_result(response)
