"""Who wants which digest — read from `identity` at the start of every run.

`identity` (Phase 6) is this project's source of truth for per-person household
facts: it already owns chore exemptions, reminder styles and arrival-notification
settings for exactly the same reason it owns this one. Nothing about a person's
preferences is stored here; this module is a read of `GET /digest-preferences`
and nothing else.

WHAT THE PREFERENCE ACTUALLY CONTROLS
-------------------------------------
Two different things, and they are worth keeping apart:

1. **What gets generated.** run.py generates the UNION of the sections the
   household asked for. A section nobody has ticked is never sent to the LLM at
   all — no synthesis call, no counter-run call, and it never reaches output/.
   That is the sense in which this is a per-person "should this be generated for
   me" toggle rather than a display setting bolted on at the end.
2. **What each surface shows.** Each person's own subset is written into the
   digest alongside the documents, and the renderer filters to it. That half is
   a **display filter, not an access control**: digest-web serves the whole
   output volume read-only to anything on the LAN, so anyone who can open the
   canvas can open the JSON behind it. Ticking a box off keeps a section off
   someone's screen and out of their narration; it does not make it secret from
   them. Say so plainly rather than implying a boundary this stack doesn't have.

FAILING SAFE MEANS GENERATING MORE, NOT LESS
--------------------------------------------
Every failure here — identity disabled, unreachable, a bad token, a malformed
response — returns None, which run.py treats as "no preferences known" and falls
back to generating every section, exactly as this component did before the
setting existed. The alternative reading of a failed lookup ("nobody asked for
anything, generate nothing") would let one unreachable container silently cost
the household its whole digest, which is far worse than one run that shows a
section someone had opted out of.

The same reasoning applies one level down: a household that runs `identity` but
has not registered anybody yet is treated as "no preferences known" too, because
an empty person table is the state of a fresh install, not a decision. Everyone
opting out of everything IS a decision, and it is honoured (loudly).
"""

import logging
import os

import requests

LOG = logging.getLogger(__name__)

DEFAULT_TIMEOUT = 10.0


def fetch(known_sections):
    """`{"people": [...], "wanted": [...]}` as identity reports it, or None.

    `known_sections` is this component's own section list — anything identity names
    that this version of digest-engine has no prompt for is dropped here rather than
    handed to a synthesis pass that would fail on the missing file.
    """
    base_url = os.environ.get("IDENTITY_URL", "").strip().rstrip("/")
    token = os.environ.get("IDENTITY_TOKEN", "").strip()
    if not base_url:
        LOG.info("IDENTITY_URL is not set, generating every digest section")
        return None

    try:
        response = requests.get(
            f"{base_url}/digest-preferences",
            headers={"Authorization": f"Bearer {token}"} if token else {},
            timeout=float(os.environ.get("IDENTITY_TIMEOUT", DEFAULT_TIMEOUT)),
        )
        response.raise_for_status()
        payload = response.json()
        if not isinstance(payload, dict):
            raise ValueError("response was not a JSON object")
    except Exception:
        LOG.warning(
            "could not read digest preferences from %s, generating every section",
            base_url,
            exc_info=True,
        )
        return None

    people = []
    for entry in payload.get("people") or []:
        if not isinstance(entry, dict) or not entry.get("name"):
            continue
        people.append(
            {
                "id": entry.get("id"),
                "name": str(entry["name"]),
                "nickname": entry.get("nickname"),
                "digest_sections": [
                    section
                    for section in known_sections
                    if section in (entry.get("digest_sections") or [])
                ],
            }
        )

    if not people:
        LOG.info("identity knows no people yet, generating every digest section")
        return None

    wanted = [
        section
        for section in known_sections
        if any(section in person["digest_sections"] for person in people)
    ]
    LOG.info(
        "digest preferences: %d person(s), generating %s",
        len(people),
        ", ".join(wanted) or "nothing — everybody has opted out of every section",
    )
    return {"people": people, "wanted": wanted}


def sections_to_generate(prefs, known_sections):
    """The sections this run should actually synthesise. Everything, when nothing is
    known about who wants what (see the module docstring on why that is the safe
    direction); otherwise exactly the union the household asked for.
    """
    if prefs is None:
        return list(known_sections)
    return list(prefs["wanted"])
