"""Pipeline execute command implementation."""

import json
from typing import Annotated, Any, Optional, cast
from uuid import UUID

import typer

from cli.commands.flag_utils import validate_uuid
from cli.commands.pipelines.execute.presenter import present_execution_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.pipeline import ExecutePipelineRequest


def pipelines_execute_command(
    pipeline_id: str = typer.Argument(
        ...,
        help="Pipeline UUID",
    ),
    wait: bool = typer.Option(
        False,
        "--wait",
        help="Wait for execution to reach a terminal state before returning",
    ),
    config: Optional[str] = typer.Option(
        None,
        "-c",
        "--config",
        help="Pipeline config as JSON string or @file.json",
    ),
    timeout: Optional[int] = typer.Option(
        None,
        "-t",
        "--timeout",
        help="Execution timeout in seconds",
    ),
    external_id: Optional[str] = typer.Option(
        None,
        "--external-id",
        help="External identifier for tracking",
    ),
    tags: Optional[str] = typer.Option(
        None,
        "--tags",
        help="Comma-separated tag paths",
    ),
    env: Annotated[
        list[str] | None,
        typer.Option(
            "--env",
            "-e",
            help="Environment variable in KEY=VALUE format (repeatable)",
        ),
    ] = None,
    metadata: Optional[str] = typer.Option(
        None,
        "--metadata",
        help="Metadata as JSON string or @file.json",
    ),
) -> None:
    """Execute a pipeline with optional configuration.

    Examples:
        alloy pipelines execute 123e4567-89ab... -c '{"topic": "AI"}'
        alloy pipelines execute 123e4567-89ab... -c @config.json
        alloy pipelines execute 123e4567-89ab... --timeout 300
        alloy pipelines execute 123e4567-89ab... -e API_KEY=secret -e REGION=us-west
        alloy pipelines execute 123e4567-89ab... --metadata '{"run_id": "abc123"}'
    """
    pipeline_uuid = validate_uuid(pipeline_id, "pipeline")

    # Parse config if provided
    config_dict: dict[str, Any] = {}
    if config:
        try:
            resolved = resolve_content(config)
        except FileContentError as e:
            raise typer.BadParameter(str(e))
        if resolved is None:
            raise typer.BadParameter("Could not resolve config content")
        try:
            config_dict = cast(dict[str, Any], json.loads(resolved))
        except json.JSONDecodeError as e:
            raise typer.BadParameter(f"Invalid JSON config: {e}")

    # Parse tags if provided
    tag_list: list[str] | None = None
    if tags:
        tag_list = [t.strip() for t in tags.split(",") if t.strip()]

    # Parse env vars if provided
    env_vars_dict: dict[str, str] | None = None
    if env:
        env_vars_dict = parse_kv_pairs(env)

    # Parse metadata if provided
    metadata_dict: dict[str, Any] | None = None
    if metadata:
        try:
            resolved = resolve_content(metadata)
        except FileContentError as e:
            raise typer.BadParameter(str(e))
        if resolved is None:
            raise typer.BadParameter("Could not resolve metadata content")
        try:
            metadata_dict = cast(dict[str, Any], json.loads(resolved))
        except json.JSONDecodeError as e:
            raise typer.BadParameter(f"Invalid JSON metadata: {e}")

    _execute_pipeline(
        pipeline_id=pipeline_uuid,
        wait=wait,
        config_dict=config_dict,
        timeout=timeout,
        external_id=external_id,
        tags=tag_list,
        env_vars=env_vars_dict,
        metadata=metadata_dict,
    )


@async_command
async def _execute_pipeline(
    pipeline_id: UUID,
    wait: bool,
    config_dict: dict[str, Any],
    timeout: Optional[int],
    external_id: Optional[str],
    tags: Optional[list[str]],
    env_vars: Optional[dict[str, str]],
    metadata: Optional[dict[str, Any]],
) -> None:
    """Execute the pipeline."""
    async with authenticated_client() as (_config, client):
        request = ExecutePipelineRequest.model_validate(
            {
                "config": config_dict,
                "timeout_seconds": timeout,
                "wait_for_completion": wait,
                "external_id": external_id,
                "tags": tags,
                "env_vars": env_vars,
                "metadata": metadata,
            }
        )

        response = await client.execute_pipeline(pipeline_id, request)

    present_execution_result(response)
