"""Content edit command implementation."""

from pathlib import Path
from typing import Any
from uuid import UUID

import typer

from cli.commands.content.edit.editor import (
    ContentValidationError,
    format_content_for_editor,
    open_editor_for_content,
    parse_edited_content,
)
from cli.infrastructure.editor import EditorError
from cli.commands.content.edit.presenter import present_content_edit_success
from cli.commands.flag_utils import parse_tags, require_exclusive, validate_uuid
from cli.infrastructure.command import async_command, authenticated_client
from cli.infrastructure.error_display import display_error
from cli.infrastructure.output import OutputService
from alloy_runtime_types.dtos.content import UpdateContentPartRequest


def content_edit_command(
    content_part_id: str = typer.Argument(
        ...,
        help="Content part UUID",
    ),
    tags: str | None = typer.Option(
        None,
        "-t",
        "--tags",
        help="Replace tags (comma-separated)",
    ),
    no_edit: bool = typer.Option(
        False,
        "--no-edit",
        help="Skip editor, only update tags",
    ),
    content: str | None = typer.Option(
        None,
        "-c",
        "--content",
        help="Inline content replacement",
    ),
    content_file: Path | None = typer.Option(
        None,
        "-f",
        "--file",
        help="Read replacement from file",
        exists=True,
        readable=True,
    ),
) -> None:
    """Edit a content part.

    By default opens $EDITOR. Use --content or --file to bypass.

    Examples:
        alloy content edit 019405e0-...
        alloy content edit <id> -t "email.final,reviewed"
        alloy content edit <id> --no-edit -t "archived"
        alloy content edit <id> -c "New content"
        alloy content edit <id> -f output.txt
    """
    content_uuid = validate_uuid(content_part_id, "content")

    # Validate exclusive content modes
    require_exclusive(
        ("--no-edit", no_edit),
        ("--content", content),
        ("--file", content_file),
    )

    # Parse tags
    tag_paths: list[str] | None = None
    if tags is not None:
        tag_paths = parse_tags(tags)

    # Validate at least one operation
    if no_edit and tag_paths is None:
        raise typer.BadParameter("--tags required with --no-edit")

    _execute_edit(
        content_part_id=content_uuid,
        tag_paths=tag_paths,
        no_edit=no_edit,
        inline_content=content,
        content_file=content_file,
    )


@async_command
async def _execute_edit(
    content_part_id: UUID,
    tag_paths: list[str] | None,
    no_edit: bool,
    inline_content: str | None,
    content_file: Path | None,
) -> None:
    """Execute edit content part operation."""
    async with authenticated_client() as (_config, client):
        current = await client.get_content_part(content_part_id)

        new_content_text: str | None = None
        new_content_structured: dict[str, Any] | None = None
        updated_content = False

        if not no_edit:
            try:
                if inline_content is not None:
                    edited_content = inline_content
                    is_structured = current.content_structured is not None
                elif content_file is not None:
                    edited_content = content_file.read_text()
                    is_structured = current.content_structured is not None
                else:
                    initial_content, is_structured = format_content_for_editor(
                        current.content_text,
                        current.content_structured,
                    )
                    edited_content = open_editor_for_content(
                        initial_content, is_structured
                    )

                    if edited_content is None:
                        output = OutputService.get()
                        output.warning("Editor cancelled")
                        raise typer.Exit(code=1)

                new_content_text, new_content_structured = parse_edited_content(
                    edited_content, is_structured
                )
                updated_content = True

            except EditorError as e:
                display_error(e)
                raise typer.Exit(code=1)
            except ContentValidationError as e:
                display_error(e)
                raise typer.Exit(code=1)

        request = UpdateContentPartRequest(
            content_text=new_content_text,
            content_structured=new_content_structured,
            tag_paths=tag_paths,
        )

        response = await client.update_content_part(content_part_id, request)

    present_content_edit_success(
        response,
        updated_content=updated_content,
        updated_tags=(tag_paths is not None),
    )
