"""Enrichment card actions — import-vault · learn · remember (v0.18 M7)."""

from __future__ import annotations

from datetime import datetime, timezone
from typing import Any

from niannian.chat.input_bus import enrichment_key_for_part
from niannian.chat.session import (
    EnrichmentAlreadyPersistedError,
    EnrichmentKindNotSupportedError,
    EnrichmentNotActionableError,
    EnrichmentNotFoundError,
    Session,
    Turn,
    TurnNotFoundError,
    TurnRecalledError,
)
from niannian.memory.disclosure import build_ingest_meta
from niannian.soul.firewall import validate_atom_meta
from niannian.storage.sync.push_after_ingest import schedule_push_after_ingest
from niannian.vault.frontmatter import serialize_md


def _now_iso() -> str:
    return datetime.now(timezone.utc).replace(microsecond=0).isoformat()


def find_turn(session: Session, turn_id: str) -> Turn:
    for turn in session.turns:
        if turn.id == turn_id:
            return turn
    raise TurnNotFoundError(turn_id)


def resolve_enrichment(turn: Turn, key: str) -> dict[str, Any]:
    if turn.role != "user":
        raise EnrichmentNotFoundError(key)
    if turn.meta.get("recalled_at"):
        raise TurnRecalledError(turn.id)
    enrichments = turn.meta.get("enrichments") or {}
    if not isinstance(enrichments, dict):
        enrichments = {}
    row = enrichments.get(key)
    if not isinstance(row, dict):
        raise EnrichmentNotFoundError(key)
    status = str(row.get("status") or "")
    if status in ("pending", "failed"):
        raise EnrichmentNotActionableError(key, status or "not_ready")
    if row.get("persisted"):
        raise EnrichmentAlreadyPersistedError(
            key,
            vault_id=str(row.get("vault_id") or "") or None,
            atom_id=str(row.get("atom_id") or "") or None,
        )
    return row


def part_for_enrichment_key(turn: Turn, key: str) -> dict[str, Any] | None:
    parts = turn.parts or []
    for part in parts:
        if enrichment_key_for_part(part) == key:
            return part
    return None


def enrichment_summary_text(kind: str, enrichment: dict[str, Any], part: dict[str, Any] | None) -> str:
    if kind == "link":
        title = str(enrichment.get("title") or "")
        snippet = str(enrichment.get("snippet") or "")
        return "\n".join(x for x in (title, snippet) if x).strip()
    if kind == "file":
        name = str(enrichment.get("name") or (part or {}).get("name") or "")
        summary = str(enrichment.get("extract_summary") or "")
        return "\n".join(x for x in (name, summary) if x).strip()
    if kind == "image":
        chunks = []
        if enrichment.get("ocr_text"):
            chunks.append(str(enrichment["ocr_text"]))
        if enrichment.get("vision_summary"):
            chunks.append(str(enrichment["vision_summary"]))
        return "\n".join(chunks).strip()
    raise EnrichmentKindNotSupportedError("", kind, "remember")


def build_vault_md(kind: str, enrichment: dict[str, Any], part: dict[str, Any] | None) -> tuple[str, dict[str, Any]]:
    hints: dict[str, Any] = {
        "source_type": kind,
        "trust_tier": "web" if kind == "link" else "user",
        "extracted_by": "niannian",
        "extracted_at": _now_iso(),
    }
    if kind == "link":
        url = str((part or {}).get("url") or "")
        title = str(enrichment.get("title") or "链接资料")
        snippet = str(enrichment.get("snippet") or "")
        body = str(enrichment.get("md_preview") or snippet)
        hints["source_url"] = url or None
        hints["title"] = title
        md_body = (
            f"## 摘要\n\n{snippet}\n\n"
            f"## 正文\n\n{body[:20_000]}\n\n"
            f"## 来源\n\n{url or '聊天链接'}"
        )
        return serialize_md(hints, md_body), hints
    if kind == "file":
        name = str(enrichment.get("name") or (part or {}).get("name") or "文件资料")
        summary = str(enrichment.get("extract_summary") or "")
        hints["title"] = name
        md_body = f"## 摘要\n\n{summary}\n\n## 文件名\n\n{name}"
        return serialize_md(hints, md_body), hints
    if kind == "image":
        title = "聊天图片"
        ocr = str(enrichment.get("ocr_text") or "")
        vision = str(enrichment.get("vision_summary") or "")
        hints["title"] = title
        body_parts = []
        if ocr:
            body_parts.append(f"## OCR\n\n{ocr}")
        if vision:
            body_parts.append(f"## 简述\n\n{vision}")
        md_body = "\n\n".join(body_parts) or ocr
        return serialize_md(hints, md_body), hints
    raise EnrichmentKindNotSupportedError("", kind, "import-vault")


def link_url_for_key(turn: Turn, key: str, enrichment: dict[str, Any]) -> str:
    part = part_for_enrichment_key(turn, key)
    url = str((part or {}).get("url") or "").strip()
    if url:
        return url
    title = str(enrichment.get("title") or "").strip()
    if title.startswith("http"):
        return title
    raise EnrichmentNotActionableError(key, "missing_url")


def update_enrichment_meta(turn: Turn, key: str, patch: dict[str, Any]) -> dict[str, Any]:
    meta = dict(turn.meta)
    enrichments = dict(meta.get("enrichments") or {})
    row = dict(enrichments.get(key) or {})
    row.update(patch)
    enrichments[key] = row
    meta["enrichments"] = enrichments
    turn.meta = meta
    return row
