"""alice invoke — Invoke a Bedrock model with a prompt."""

from __future__ import annotations

import sys

import click
from botocore.exceptions import BotoCoreError, ClientError

from alice_cli import personality
from alice_cli.aws.bedrock_context import create_bedrock_context
from alice_cli.bedrock_utils import build_converse_kwargs, parse_converse_response
from alice_cli.console import (
    err_console,
    print_banner,
    print_rule,
    print_status,
    print_success,
    spinner,
)
from alice_cli.errors import AliceCLIError
from alice_cli.logging import get_logger
from alice_cli.models import DEFAULT_MODEL_ALIAS, SaveFormat, model_help_text, resolve_model_id
from alice_cli.save import save_session

log = get_logger(__name__)


@click.command("invoke", context_settings={"ignore_unknown_options": True})
@click.option("--model-id", default=DEFAULT_MODEL_ALIAS, help=model_help_text())
@click.option(
    "-o",
    "--output",
    "save_path",
    default=None,
    type=click.Path(),
    help="Write session output to a local file",
)
@click.option(
    "-f",
    "--format",
    "fmt",
    default="markdown",
    type=click.Choice(["markdown", "json", "text"], case_sensitive=False),
    help="Output file format (default: markdown)",
)
@click.argument("prompt", nargs=-1, type=click.UNPROCESSED, required=True)
@click.pass_context
def invoke_cmd(
    ctx: click.Context, model_id: str, save_path: str | None, fmt: str, prompt: tuple[str, ...]
) -> None:
    """Send a prompt to a Bedrock model."""
    config = ctx.obj["config"]

    prompt_text = " ".join(prompt).strip()
    if not prompt_text:
        raise AliceCLIError("Please provide a prompt after the options.")

    print_banner(personality.BANNER, config.quiet)

    # ── Authenticate and build Bedrock client ─────────────────────────────────
    context = create_bedrock_context(config)
    resolved_id = resolve_model_id(model_id, context.inference_profile_arns)
    if resolved_id != model_id:
        print_status(personality.status_resolved_profile(model_id), config.quiet)
        log.debug("model_resolved_to_profile", alias=model_id, resolved=resolved_id)

    # ── Invoke model ──────────────────────────────────────────────────────────
    log.debug(
        "bedrock_invoke_starting",
        model_alias=model_id,
        model_id=resolved_id,
        prompt_length=len(prompt_text),
        username=context.username,
    )
    with spinner(personality.status_invoking_model(model_id), config.quiet):
        try:
            response = context.client.converse(
                **build_converse_kwargs(
                    resolved_id,
                    [{"role": "user", "content": [{"text": prompt_text}]}],
                )
            )
        except (ClientError, BotoCoreError) as exc:
            from alice_cli.error_handler import extract_aws_error, handle_bedrock_error

            error = extract_aws_error(exc)
            log.error("bedrock_invoke_failed", model_id=resolved_id, **error.to_dict())
            raise handle_bedrock_error(exc, model_id=resolved_id) from exc

    output_text, tokens = parse_converse_response(response)
    log.info(
        "bedrock_invoke_success",
        model_id=resolved_id,
        input_tokens=tokens.input,
        output_tokens=tokens.output,
    )
    log.debug("response_parsed", response_length=len(output_text))

    # ── Write response to stdout (machine-readable) ───────────────────────────
    # Response text always goes to stdout so it can be piped or redirected.
    # Status/UX output (banner, spinner, success) stays on stderr.
    if output_text.strip():
        click.echo(output_text)
    else:
        click.echo("")

    # When stdout is a TTY, also render a Markdown preview on stderr for readability.
    if sys.stdout.isatty() and not config.quiet and output_text.strip():
        from rich.markdown import Markdown

        print_rule(config.quiet)
        err_console.print(Markdown(output_text))
        print_rule(config.quiet)
    elif not config.quiet:
        print_success(personality.status_model_ready(model_id), config.quiet)

    if save_path:
        save_session(
            path=save_path,
            prompt=prompt_text,
            model=model_id,
            content=output_text,
            quiet=config.quiet,
            fmt=SaveFormat(fmt.lower()),
        )
