from pathlib import Path
from typing import Annotated, Any, Optional

import typer

from cli.commands.flag_utils import require_exclusive, require_one_of
from cli.commands.templates.validate.presenter import present_validate_result
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.templates import ValidateTemplateRequest


def templates_validate_command(
    content_file: Optional[Path] = typer.Option(
        None,
        "-f",
        "--file",
        help="Read template content from file",
        exists=True,
        readable=True,
    ),
    content: Optional[str] = typer.Option(
        None,
        "-c",
        "--content",
        help="Inline template content (or @file)",
    ),
    variables: Annotated[
        Optional[list[str]],
        typer.Option(
            "-v",
            "--var",
            help="Variable (key=value, key:=json, or key={...}/[...] for nested JSON). Repeatable.",
        ),
    ] = None,
) -> None:
    """Validate template content without saving it."""
    require_exclusive(("--file", content_file), ("--content", content))
    require_one_of(("--file", content_file), ("--content", content))

    variables_dict = parse_kv_pairs(variables, parse_object_array_strings=True)

    _execute_validate_from_flags(
        content_file=content_file,
        content=content,
        variables_dict=variables_dict,
    )


def _execute_validate_from_flags(
    *,
    content_file: Path | None,
    content: str | None,
    variables_dict: dict[str, Any] | None,
) -> None:
    try:
        resolved_content = resolve_content(content)
    except FileContentError as e:
        raise typer.BadParameter(str(e))

    if content_file is not None:
        template_content = content_file.read_text()
    else:
        template_content = resolved_content or ""

    if not template_content.strip():
        raise typer.BadParameter("Template content cannot be empty")

    request = ValidateTemplateRequest(
        content=template_content,
        variables=variables_dict or {},
    )
    _execute_validate(request)


@async_command
async def _execute_validate(request: ValidateTemplateRequest) -> None:
    async with authenticated_client() as (_config, client):
        response = await client.validate_template(request)

    present_validate_result(response)
    if not response.is_renderable:
        raise typer.Exit(1)
