"""Disclosure 召回过滤与 ingest meta 构建。"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Literal

from niannian.memory.meta import AtomMeta, DisclosureMeta, ProvenanceMeta, parse_atom_meta
from niannian.schemas.models import Atom

RecallMode = Literal["subject", "object"]


@dataclass(frozen=True)
class RecallContext:
    mode: RecallMode
    object_id: str | None = None

    @classmethod
    def from_session_meta(cls, meta: dict[str, Any] | None) -> RecallContext:
        session = meta or {}
        oid = session.get("current_object_id")
        if oid is not None and str(oid).strip():
            return cls(mode="object", object_id=str(oid).strip())
        return cls(mode="subject")

    def to_dict(self) -> dict[str, Any]:
        return {"mode": self.mode, "object_id": self.object_id}


def atom_visible_for_recall(atom: Atom, ctx: RecallContext) -> bool:
    """F7：subject 仅 subject atom；object 须 told_to 含当前客体。"""
    parsed = parse_atom_meta(atom.meta if isinstance(atom.meta, dict) else None)
    if ctx.mode == "subject":
        return parsed.memory_scope != "object"
    if ctx.mode == "object":
        if parsed.memory_scope != "object":
            return False
        if not ctx.object_id:
            return False
        if parsed.object_anchor and parsed.object_anchor != ctx.object_id:
            return False
        return ctx.object_id in parsed.disclosure.told_to
    return False


def build_ingest_meta(session_meta: dict[str, Any] | None) -> dict[str, Any]:
    """Chat ingest 时写入 atom.meta。"""
    session = session_meta or {}
    oid = session.get("current_object_id")
    if oid is not None and str(oid).strip():
        oid_str = str(oid).strip()
        disc_raw = session.get("ingest_disclosure")
        disc = disc_raw if isinstance(disc_raw, dict) else {}
        told = disc.get("told_to")
        told_list = [str(x) for x in told if isinstance(x, str)] if isinstance(told, list) else []
        entities = disc.get("entities")
        entity_list = [str(x) for x in entities if isinstance(x, str)] if isinstance(entities, list) else []
        meta = AtomMeta(
            memory_scope="object",
            object_anchor=oid_str,
            subject_eligible=False,
            disclosure=DisclosureMeta(
                told_to=told_list,
                entities=entity_list,
                source_user=str(disc["source_user"]) if disc.get("source_user") is not None else None,
            ),
        )
        if session.get("user_role") == "guest" or session.get("user_id") == "guest":
            meta.provenance = ProvenanceMeta(trust_tier="guest_reference")
        return meta.to_dict()
    return AtomMeta(memory_scope="subject", subject_eligible=True).to_dict()
