"""alice chat — Persistent multi-turn conversation with a Bedrock model."""

from __future__ import annotations

import uuid

import click
from botocore.exceptions import ClientError
from prompt_toolkit import PromptSession
from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
from rich.markdown import Markdown

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.constants import get_memory_bucket
from alice_cli.errors import AliceCLIError
from alice_cli.locker import CloudLocker
from alice_cli.models import (
    DEFAULT_MODEL_ALIAS,
    ChatMessage,
    TokenUsage,
    model_help_text,
    resolve_model_id,
)
from alice_cli.session_record import build_session_record


@click.command("chat")
@click.option("--model-id", default=DEFAULT_MODEL_ALIAS, help=model_help_text())
@click.option("--session-id", default=None, help="Resume a previous chat session by ID")
@click.option("--system", default=None, help="System prompt for the conversation")
@click.pass_context
def chat_cmd(
    ctx: click.Context,
    model_id: str,
    session_id: str | None,
    system: str | None,
) -> None:
    """Have a multi-turn conversation with a model.

    \b
    Examples:
        alice chat
        alice chat --model-id opus
        alice chat --system "You are a helpful tutor"
        alice chat --session-id <uuid>
    """
    config = ctx.obj["config"]

    print_banner(personality.BANNER, config.quiet)

    # ── Authenticate and build Bedrock client ─────────────────────────
    context = create_bedrock_context(config)
    username = context.username
    resolved_id = resolve_model_id(model_id, context.inference_profile_arns)
    client = context.client

    # ── Session setup ─────────────────────────────────────────────────
    locker = CloudLocker(
        config=config,
        username=username,
        bucket=get_memory_bucket(config.namespace, config.environment),
    )
    messages: list[ChatMessage] = []
    total_input_tokens = 0
    total_output_tokens = 0

    if session_id:
        # Resume existing session
        try:
            record = locker.load_session(session_id, "chat")
            meta = record.metadata or {}
            for m in meta.get("messages", []):
                messages.append(ChatMessage(role=m["role"], content=m["content"]))
            if not system and meta.get("system"):
                system = meta["system"]
            print_success(f"Resumed session {session_id}", config.quiet)
        except Exception as exc:
            raise AliceCLIError(f"Could not resume session: {exc}") from exc
    else:
        session_id = str(uuid.uuid4())
        print_status(f"New session: {session_id}", config.quiet)

    # ── REPL ──────────────────────────────────────────────────────────
    print_rule(config.quiet)
    if not config.quiet:
        err_console.print(
            f"  [bold]Chat[/bold] with [cyan]{model_id}[/cyan]  •  "
            f"Type [dim]exit[/dim], [dim]quit[/dim], or [dim]Ctrl+D[/dim] to end.\n"
        )

    prompt_session: PromptSession[str] = PromptSession(
        auto_suggest=AutoSuggestFromHistory(),
        multiline=False,
    )

    first_prompt: str | None = None

    while True:
        # ── Read user input ───────────────────────────────────────────
        try:
            user_input = prompt_session.prompt("You: ")
        except (EOFError, KeyboardInterrupt):
            break

        stripped = user_input.strip()
        if not stripped:
            continue
        if stripped.lower() in ("exit", "quit"):
            break

        if first_prompt is None:
            first_prompt = stripped

        # ── Append user message ───────────────────────────────────────
        messages.append(ChatMessage(role="user", content=stripped))

        # ── Call Converse API ─────────────────────────────────────────
        api_messages = [{"role": m.role, "content": [{"text": m.content}]} for m in messages]
        with spinner(personality.status_invoking_model(model_id), config.quiet):
            try:
                response = client.converse(
                    **build_converse_kwargs(resolved_id, api_messages, system_prompt=system)
                )
            except ClientError as exc:
                err_console.print(f"  [red]✗[/red] Bedrock API error: {exc}")
                # Remove the user message so they can retry
                messages.pop()
                continue

        assistant_text, turn_tokens = parse_converse_response(response)
        total_input_tokens += turn_tokens.input
        total_output_tokens += turn_tokens.output

        # ── Append assistant message ──────────────────────────────────
        messages.append(ChatMessage(role="assistant", content=assistant_text))

        # ── Display response ──────────────────────────────────────────
        print_rule(config.quiet)
        if assistant_text.strip():
            err_console.print(Markdown(assistant_text))
        else:
            err_console.print("[dim](empty response)[/dim]")
        print_rule(config.quiet)

    # ── Persist session ───────────────────────────────────────────────
    if messages:
        record = build_session_record(
            record_type="chat",
            model=resolved_id,
            prompt=first_prompt or "",
            response=None,
            tokens=TokenUsage(
                input=total_input_tokens,
                output=total_output_tokens,
                total=total_input_tokens + total_output_tokens,
            ),
            metadata={
                "messages": [{"role": m.role, "content": m.content} for m in messages],
                "system": system,
                "session_id": session_id,
            },
        )
        # Override the auto-generated id with our session_id
        record = type(record)(
            id=session_id,
            type=record.type,
            timestamp=record.timestamp,
            model=record.model,
            prompt=record.prompt,
            response=record.response,
            tokens=record.tokens,
            metadata=record.metadata,
        )
        try:
            locker.persist(record, "chat")
            print_success(f"Session saved: {session_id}", config.quiet)
        except Exception as exc:
            err_console.print(f"[yellow]⚠ Could not save session: {exc}[/yellow]")
    else:
        if not config.quiet:
            err_console.print("  [dim]No messages to save.[/dim]")

    if not config.quiet:
        err_console.print("\n  [green]✓[/green] Chat ended. Goodbye!")
