"""Core 页数据聚合 — mind · memories · baseline。"""

from __future__ import annotations

import json
from typing import Any, TYPE_CHECKING

from niannian.memory.meta import parse_atom_meta
from niannian.soul.assembly import build_values_gate
from niannian.soul.baseline import BaselineManager
from niannian.soul.drift import DriftDetector
from niannian.soul.firewall import is_subject_summary
from niannian.soul.values import values_summary

if TYPE_CHECKING:
    from niannian.client import NianNian


class CoreMindService:
    def __init__(self, nn: NianNian) -> None:
        self._nn = nn
        self._store = nn._subject_store
        self._baseline = BaselineManager(self._store)

    def get_mind(self) -> dict[str, Any]:
        pack = self._store.load_subject_pack()
        values = pack.get("values") if isinstance(pack.get("values"), dict) else {}
        narrative = pack.get("narrative") if isinstance(pack.get("narrative"), dict) else {}
        emotion = pack.get("emotion") if isinstance(pack.get("emotion"), dict) else {}
        focus = pack.get("focus") if isinstance(pack.get("focus"), dict) else {}
        reflection = self._store.load_reflection()

        drift_report = DriftDetector(self._store, self._baseline).check(record_audit=False)
        pending = [
            t for t in (reflection.get("pending_thoughts") or []) if isinstance(t, dict) and t.get("status") == "pending"
        ]
        recent_reviews = self._recent_reviews(reflection.get("reviews") or [])

        return {
            "values_summary": values_summary(values),
            "values_gate": build_values_gate(values),
            "narrative": {
                "lines": list(narrative.get("lines") or [])[:20],
            },
            "open_threads": list(pack.get("open_threads") or [])[:20],
            "main_thoughts": self._main_thoughts(),
            "mood": {
                "mood": emotion.get("mood") or "calm",
                "updated_at": emotion.get("updated_at"),
            },
            "regime": str(focus.get("regime") or "companion"),
            "drift": {
                "status": drift_report.status,
                "last_check_at": drift_report.checked_at,
                "summary": drift_report.summary,
                "baseline_id": drift_report.baseline_id,
                "diffs": drift_report.diffs,
            },
            "evolution_tail": self._evolution_tail(),
            "cultural_learning": self._cultural_summary(),
            "web_learning": self._web_learning_summary(),
            "correction_thread_tail": self._correction_thread_tail(),
            "reflection": {
                "pending_count": len(pending),
                "recent_reviews": recent_reviews,
            },
        }

    def list_memories(
        self,
        *,
        scope: str = "subject",
        limit: int = 50,
        cursor: str | None = None,
        project: str | None = None,
    ) -> dict[str, Any]:
        if scope != "subject":
            return {"items": [], "next_cursor": None}
        lim = max(1, min(int(limit), 100))
        proj = project or self._nn.project
        atoms = self._nn._left.list_atoms(project=proj, limit=2000)
        if proj != "global":
            atoms += [a for a in self._nn._left.list_atoms(project="global", limit=500) if a not in atoms]

        filtered = []
        for atom in atoms:
            meta = parse_atom_meta(atom.meta if isinstance(atom.meta, dict) else None)
            if meta.memory_scope == "object":
                continue
            if meta.subject_eligible is False:
                continue
            if meta.provenance.trust_tier == "guest_reference":
                continue
            filtered.append(atom)

        filtered.sort(key=lambda a: a.created_at, reverse=True)
        if cursor:
            ids = [a.id for a in filtered]
            if cursor in ids:
                start = ids.index(cursor) + 1
                filtered = filtered[start:]

        page = filtered[: lim + 1]
        has_more = len(page) > lim
        items_atoms = page[:lim]
        items = [
            {
                "id": a.id,
                "text_preview": a.raw_text[:240],
                "tags": list(a.tags or []),
                "created_at": a.created_at,
                "reality_anchor": (
                    parse_atom_meta(a.meta if isinstance(a.meta, dict) else None).provenance.reality_anchor
                ),
                "subject_eligible": parse_atom_meta(
                    a.meta if isinstance(a.meta, dict) else None
                ).subject_eligible,
            }
            for a in items_atoms
        ]
        next_cursor = items_atoms[-1].id if has_more and items_atoms else None
        return {"items": items, "next_cursor": next_cursor}

    def snapshot_baseline(self, *, label: str | None = None) -> dict[str, Any]:
        dest = self._baseline.snapshot(label=label)
        meta_path = dest / "meta.json"
        meta = json.loads(meta_path.read_text(encoding="utf-8")) if meta_path.is_file() else {}
        return {
            "id": meta.get("id") or dest.name,
            "label": meta.get("label"),
            "created_at": meta.get("created_at"),
        }

    def _main_thoughts(self) -> list[dict[str, Any]]:
        summaries = self._nn._hippocampus.store.read_summaries()
        rows: list[dict[str, Any]] = []
        for key, item in summaries.items():
            if not isinstance(item, dict):
                continue
            if not is_subject_summary(str(key), item):
                continue
            text = str(item.get("text") or "").strip()
            if not text:
                continue
            source = "dream"
            if str(key).startswith("thread:"):
                source = "self_reflect"
            rows.append(
                {
                    "at": item.get("updated_at"),
                    "text": text[:400],
                    "source": source,
                    "atom_ids": list(item.get("atom_ids") or []),
                    "tag": str(key),
                }
            )
        rows.sort(key=lambda r: str(r.get("at") or ""), reverse=True)
        return rows[:10]

    @staticmethod
    def _recent_reviews(reviews: list[Any]) -> list[dict[str, Any]]:
        out: list[dict[str, Any]] = []
        for row in reversed(reviews[-30:]):
            if not isinstance(row, dict):
                continue
            out.append(
                {
                    "thought_id": row.get("thought_id"),
                    "text_preview": None,
                    "score": row.get("score"),
                    "verdict": row.get("verdict"),
                    "doubt": row.get("seat"),
                    "at": row.get("at"),
                    "trigger": row.get("trigger"),
                }
            )
            if len(out) >= 8:
                break
        return out

    def _evolution_tail(self) -> list[dict[str, Any]]:
        path = self._store.subject_root / "evolution.jsonl"
        if not path.is_file():
            return []
        lines = path.read_text(encoding="utf-8").splitlines()
        tail: list[dict[str, Any]] = []
        for line in reversed(lines[-20:]):
            line = line.strip()
            if not line:
                continue
            try:
                row = json.loads(line)
            except json.JSONDecodeError:
                continue
            if isinstance(row, dict):
                tail.append(row)
            if len(tail) >= 10:
                break
        return tail

    def _cultural_summary(self) -> dict[str, Any]:
        from niannian.soul.cultural_learning import CulturalLearningService

        svc = CulturalLearningService(self._store, self._nn._config, home=self._nn._home)
        data = svc.to_api_dict()
        return {
            "enabled": data.get("enabled"),
            "auto_learning": data.get("auto_learning"),
            "personality_bootstrap_complete": data.get("personality_bootstrap_complete"),
            "allow_values_update": data.get("allow_values_update"),
            "last_batch_at": data.get("last_batch_at"),
            "recent_syntheses": data.get("recent_syntheses") or [],
        }

    def _web_learning_summary(self) -> dict[str, Any]:
        from niannian.soul.web_learning import WebLearningService

        svc = WebLearningService(self._store, self._nn._config, home=self._nn._home)
        data = svc.to_api_dict()
        return {
            "enabled": data.get("enabled"),
            "auto_learning": data.get("auto_learning"),
            "schedule_label": data.get("schedule_label"),
            "personality_bootstrap_complete": data.get("personality_bootstrap_complete"),
            "learning_minutes_today": data.get("learning_minutes_today"),
            "duration_minutes": data.get("duration_minutes"),
            "last_batch_at": data.get("last_batch_at"),
            "recent_syntheses": data.get("recent_syntheses") or [],
        }

    def _correction_thread_tail(self) -> list[dict[str, Any]]:
        from niannian.core.correct_service import CorrectionThreadStore

        return CorrectionThreadStore(self._store.subject_root).tail(10)
