"""Interactive REPL and one-shot mode for the Keiro CLI.

Handles three invocation patterns:

- ``keiro`` — interactive streaming chat REPL
- ``keiro "prompt"`` — one-shot: print response, exit
- ``echo ctx | keiro "prompt"`` — pipe stdin as context

When stdout is not a TTY (piped to another program), output is raw text
with no decorations, colors, or latency display.
"""

from __future__ import annotations

import sys
import time
from typing import Iterator

from keiro.defaults import DEFAULT_MODEL


def _is_tty_out() -> bool:
    return sys.stdout.isatty()


def _is_tty_in() -> bool:
    return sys.stdin.isatty()


def _read_stdin_context() -> str | None:
    """Read piped stdin content. Returns None if stdin is a TTY."""
    if _is_tty_in():
        return None
    try:
        return sys.stdin.read()
    except (OSError, UnicodeDecodeError):
        return None


def _stream_response(
    chunks: Iterator[str],
    *,
    decorated: bool,
) -> tuple[str, float]:
    """Consume a streaming response, printing chunks as they arrive.

    Args:
        chunks: Iterator of text chunks from the API.
        decorated: If True, print with formatting. If False, raw text only.

    Returns:
        Tuple of (full response text, elapsed seconds).
    """
    start = time.monotonic()
    full_text: list[str] = []

    for chunk in chunks:
        full_text.append(chunk)
        sys.stdout.write(chunk)
        sys.stdout.flush()

    elapsed = time.monotonic() - start

    if decorated:
        sys.stdout.write("\n")
        sys.stdout.flush()

    return "".join(full_text), elapsed


def _print_latency(elapsed: float) -> None:
    """Print latency in dim text."""
    if elapsed < 1.0:
        label = f"{elapsed * 1000:.0f}ms"
    else:
        label = f"{elapsed:.1f}s"
    sys.stdout.write(f"\033[2m{label}\033[0m\n")
    sys.stdout.flush()


def one_shot(prompt: str, *, model: str, context: str | None = None) -> int:
    """Run a single prompt, stream the response, and exit.

    Args:
        prompt: User prompt text.
        model: Model identifier.
        context: Optional piped context to prepend as a system message.

    Returns:
        Exit code.
    """
    from keiro.model_api import ModelsAPI

    decorated = _is_tty_out()
    api = ModelsAPI()

    try:
        kwargs: dict[str, object] = {}
        if context:
            kwargs["instructions"] = context

        chunks = api.responses_stream(model, input=prompt, **kwargs)
        _, elapsed = _stream_response(chunks, decorated=decorated)

        if decorated:
            _print_latency(elapsed)
        else:
            # Ensure trailing newline for piped output.
            sys.stdout.write("\n")
            sys.stdout.flush()
    except KeyboardInterrupt:
        sys.stdout.write("\n")
        return 130
    except Exception as exc:
        sys.stderr.write(f"error: {exc}\n")
        return 1
    finally:
        api.close()

    return 0


def repl(*, model: str) -> int:
    """Run an interactive streaming chat REPL.

    Args:
        model: Default model identifier.

    Returns:
        Exit code.
    """
    from keiro.model_api import ModelsAPI

    api = ModelsAPI()

    _print_welcome(model)

    try:
        while True:
            try:
                prompt = input(f"\033[1m>\033[0m ")
            except EOFError:
                sys.stdout.write("\n")
                break

            prompt = prompt.strip()
            if not prompt:
                continue

            if prompt.lower() in ("exit", "quit", "/q"):
                break

            sys.stdout.write("\n")
            try:
                chunks = api.responses_stream(model, input=prompt)
                _, elapsed = _stream_response(chunks, decorated=True)
                _print_latency(elapsed)
            except Exception as exc:
                sys.stderr.write(f"error: {exc}\n")
            sys.stdout.write("\n")

    except KeyboardInterrupt:
        sys.stdout.write("\n")
    finally:
        api.close()

    return 0


def _print_welcome(model: str) -> None:
    """Print a minimal welcome banner."""
    sys.stdout.write(f"\033[1mkeiro\033[0m \033[2m({model})\033[0m\n")
    sys.stdout.write("\033[2mType a prompt. Ctrl-C or 'exit' to quit.\033[0m\n\n")
    sys.stdout.flush()
