"""The Narrator role service (charter §5). Renders the digest, routes the model,
calls Ollama with one retry, logs the call (§10), and returns raw prose — tags
left intact for the client's TagExtractor to harvest (§2/§6). Raises ModelError
on failure for the handler to map to a 502.
"""

import random
from time import perf_counter

from . import call_log, ollama_client, prompts, routing


def run(canon_log: dict) -> str:
    cfg = routing.for_role("narrator")
    options = {**cfg.options, "seed": random.randint(0, 2**31 - 1)}
    messages = [
        {"role": "system", "content": prompts.system_prompt("narrator")},
        {"role": "user", "content": prompts.render_digest(canon_log)},
    ]

    start = perf_counter()
    try:
        text = ollama_client.chat(cfg.model, messages, options, think=cfg.think)
    except ollama_client.ModelError as exc:
        call_log.record(
            role="narrator", model=cfg.model, options=options, messages=messages,
            canon_log=canon_log, ok=False,
            latency_ms=int((perf_counter() - start) * 1000), error=str(exc),
        )
        raise

    call_log.record(
        role="narrator", model=cfg.model, options=options, messages=messages,
        canon_log=canon_log, ok=True,
        latency_ms=int((perf_counter() - start) * 1000), response=text,
    )
    return text
