"""Boot, epochs, summaries, narratives, drives, relationships, entity models,
temporal, search, status, and format_memory operations for Kernle."""

import logging
import uuid
from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional

from kernle.storage import SelfNarrative, Summary

logger = logging.getLogger(__name__)


class ManagersMixin:
    """Boot, epochs, summaries, narratives, drives-load, relationships-load,
    entity models, temporal, search, status, and format_memory operations."""

    # =========================================================================
    # BOOT CONFIG
    # =========================================================================

    def boot_set(self, key: str, value: str) -> None:
        """Set a boot config value."""
        self._storage.boot_set(key, value)
        self._export_boot_file()

    def boot_get(self, key: str, default: Optional[str] = None) -> Optional[str]:
        """Get a boot config value."""
        return self._storage.boot_get(key, default)

    def boot_list(self) -> Dict[str, str]:
        """List all boot config values."""
        return self._storage.boot_list()

    def boot_delete(self, key: str) -> bool:
        """Delete a boot config value."""
        result = self._storage.boot_delete(key)
        if result:
            self._export_boot_file()
        return result

    def boot_clear(self) -> int:
        """Clear all boot config."""
        count = self._storage.boot_clear()
        if count > 0:
            self._export_boot_file()
        return count

    def _export_boot_file(self) -> None:
        """Auto-export boot config to flat file.

        Writes to ~/.kernle/{stack_id}/boot.md with 0600 permissions.
        """
        from kernle.utils import get_kernle_home

        config = self.boot_list()
        if not config:
            # Remove boot file if config is empty
            boot_path = get_kernle_home() / self.stack_id / "boot.md"
            if boot_path.exists():
                boot_path.unlink()
            return

        now_str = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC")
        lines = [
            "# Boot Config",
            "",
        ]
        for k, v in sorted(config.items()):
            lines.append(f"- {k}: {v}")
        lines.append("")
        lines.append(f"<!-- Auto-generated by kernle at {now_str} -->")
        lines.append(
            f"<!-- Do not edit manually. Use: kernle -s {self.stack_id} boot set <key> <value> -->"
        )
        lines.append("")

        boot_path = get_kernle_home() / self.stack_id / "boot.md"
        boot_path.parent.mkdir(parents=True, exist_ok=True)
        boot_path.write_text("\n".join(lines), encoding="utf-8")

        # Set secure file permissions (owner read/write only)
        try:
            import os

            os.chmod(boot_path, 0o600)
        except OSError:
            pass  # Best effort

    def _format_boot_section(self) -> list[str]:
        """Format boot config as markdown lines for inclusion in load/export-cache."""
        config = self.boot_list()
        if not config:
            return []
        lines = ["## Boot Config"]
        for k, v in sorted(config.items()):
            lines.append(f"- {k}: {v}")
        lines.append("")
        return lines

    # =========================================================================
    # EPOCH MANAGEMENT
    # =========================================================================

    def epoch_create(
        self,
        name: str,
        trigger_type: str = "declared",
        trigger_description: Optional[str] = None,
    ) -> str:
        """Create a new epoch (temporal era).

        Automatically closes any currently open epoch before creating a new one.

        Args:
            name: Name for this epoch (e.g., "onboarding", "production-v2")
            trigger_type: What triggered this epoch (declared, detected, system)
            trigger_description: Optional description of the trigger event

        Returns:
            The new epoch's ID
        """
        from kernle.storage.base import Epoch

        name = self._validate_string_input(name, "name", 200)
        if trigger_type not in ("declared", "detected", "system"):
            raise ValueError("trigger_type must be one of: declared, detected, system")

        if trigger_description is not None:
            trigger_description = self._validate_string_input(
                trigger_description, "trigger_description", 500
            )

        # Close any currently open epoch
        current = self._storage.get_current_epoch()
        if current:
            self._storage.close_epoch(current.id, summary=None)

        # Determine next epoch number
        epochs = self._storage.get_epochs(limit=1)
        next_number = (epochs[0].epoch_number + 1) if epochs else 1

        epoch = Epoch(
            id=str(uuid.uuid4()),
            stack_id=self.stack_id,
            epoch_number=next_number,
            name=name,
            started_at=datetime.now(timezone.utc),
            trigger_type=trigger_type,
            trigger_description=trigger_description,
        )

        return self._storage.save_epoch(epoch)

    def epoch_close(
        self,
        epoch_id: Optional[str] = None,
        summary: Optional[str] = None,
    ) -> bool:
        """Close an epoch.

        Args:
            epoch_id: ID of epoch to close (defaults to current epoch)
            summary: Optional summary of the epoch

        Returns:
            True if closed, False if not found or already closed
        """
        if epoch_id is None:
            current = self._storage.get_current_epoch()
            if not current:
                return False
            epoch_id = current.id
        else:
            epoch_id = self._validate_string_input(epoch_id, "epoch_id", 100)

        if summary is not None:
            summary = self._validate_string_input(summary, "summary", 2000)

        return self._storage.close_epoch(epoch_id, summary=summary)

    def get_current_epoch(self):
        """Get the currently active epoch, if any."""
        return self._storage.get_current_epoch()

    def get_epochs(self, limit: int = 100):
        """Get all epochs, most recent first."""
        return self._storage.get_epochs(limit=limit)

    def get_epoch(self, epoch_id: str):
        """Get a specific epoch by ID."""
        epoch_id = self._validate_string_input(epoch_id, "epoch_id", 100)
        return self._storage.get_epoch(epoch_id)

    # =========================================================================
    # SUMMARIES (Fractal Summarization)
    # =========================================================================

    def summary_save(
        self,
        content: str,
        scope: str,
        period_start: str,
        period_end: str,
        key_themes: Optional[List[str]] = None,
        supersedes: Optional[List[str]] = None,
        epoch_id: Optional[str] = None,
    ) -> str:
        """Create or update a summary.

        Args:
            content: SI-written narrative compression
            scope: Temporal scope ('month', 'quarter', 'year', 'decade', 'epoch')
            period_start: Start of the period (ISO date)
            period_end: End of the period (ISO date)
            key_themes: Key themes/topics covered
            supersedes: IDs of lower-scope summaries this covers
            epoch_id: Associated epoch ID

        Returns:
            The summary ID
        """

        valid_scopes = ("month", "quarter", "year", "decade", "epoch")
        if scope not in valid_scopes:
            raise ValueError(f"scope must be one of: {', '.join(valid_scopes)}")

        content = self._validate_string_input(content, "content", 10000)
        period_start = self._validate_string_input(period_start, "period_start", 30)
        period_end = self._validate_string_input(period_end, "period_end", 30)

        summary = Summary(
            id=str(uuid.uuid4()),
            stack_id=self.stack_id,
            scope=scope,
            period_start=period_start,
            period_end=period_end,
            epoch_id=epoch_id,
            content=content,
            key_themes=key_themes,
            supersedes=supersedes,
            is_protected=True,
            created_at=datetime.now(timezone.utc),
        )

        return self._storage.save_summary(summary)

    def summary_get(self, summary_id: str):
        """Get a specific summary by ID."""
        summary_id = self._validate_string_input(summary_id, "summary_id", 100)
        return self._storage.get_summary(summary_id)

    def summary_list(self, scope: Optional[str] = None):
        """Get all summaries, optionally filtered by scope."""
        if scope:
            valid_scopes = ("month", "quarter", "year", "decade", "epoch")
            if scope not in valid_scopes:
                raise ValueError(f"scope must be one of: {', '.join(valid_scopes)}")
        return self._storage.list_summaries(self.stack_id, scope=scope)

    # =========================================================================
    # SELF-NARRATIVE API
    # =========================================================================

    def narrative_save(
        self,
        content: str,
        narrative_type: str = "identity",
        key_themes: Optional[List[str]] = None,
        unresolved_tensions: Optional[List[str]] = None,
        epoch_id: Optional[str] = None,
    ) -> str:
        """Create or update a self-narrative.

        Deactivates existing active narratives of the same type first,
        then saves the new one as active.

        Args:
            content: The narrative content
            narrative_type: 'identity', 'developmental', or 'aspirational'
            key_themes: Key themes in the narrative
            unresolved_tensions: Unresolved tensions or contradictions
            epoch_id: Associated epoch ID

        Returns:
            The narrative ID
        """
        valid_types = ("identity", "developmental", "aspirational")
        if narrative_type not in valid_types:
            raise ValueError(f"narrative_type must be one of: {', '.join(valid_types)}")

        content = self._validate_string_input(content, "content", 10000)

        # Deactivate existing active narratives of the same type
        self._storage.deactivate_self_narratives(self.stack_id, narrative_type)

        narrative = SelfNarrative(
            id=str(uuid.uuid4()),
            stack_id=self.stack_id,
            content=content,
            narrative_type=narrative_type,
            epoch_id=epoch_id,
            key_themes=key_themes,
            unresolved_tensions=unresolved_tensions,
            is_active=True,
            created_at=datetime.now(timezone.utc),
        )

        return self._storage.save_self_narrative(narrative)

    def narrative_get_active(self, narrative_type: str = "identity") -> Optional[SelfNarrative]:
        """Get the active self-narrative for a given type.

        Args:
            narrative_type: 'identity', 'developmental', or 'aspirational'

        Returns:
            The active narrative or None
        """
        narratives = self._storage.list_self_narratives(
            self.stack_id, narrative_type=narrative_type, active_only=True
        )
        return narratives[0] if narratives else None

    def narrative_list(
        self,
        narrative_type: Optional[str] = None,
        active_only: bool = True,
    ) -> List[SelfNarrative]:
        """List self-narratives, optionally filtered.

        Args:
            narrative_type: Filter by type (identity, developmental, aspirational)
            active_only: If True, only return active narratives

        Returns:
            List of matching narratives
        """
        if narrative_type:
            valid_types = ("identity", "developmental", "aspirational")
            if narrative_type not in valid_types:
                raise ValueError(f"narrative_type must be one of: {', '.join(valid_types)}")
        return self._storage.list_self_narratives(
            self.stack_id, narrative_type=narrative_type, active_only=active_only
        )

    # =========================================================================
    # DRIVES (load) & RELATIONSHIPS (load)
    # =========================================================================

    def load_drives(self) -> List[Dict[str, Any]]:
        """Load current drive states."""
        drives = self._storage.get_drives()
        return [
            {
                "id": d.id,
                "drive_type": d.drive_type,
                "intensity": d.intensity,
                "last_satisfied_at": d.updated_at.isoformat() if d.updated_at else None,
                "focus_areas": d.focus_areas,
            }
            for d in drives
        ]

    def load_relationships(self, limit: int = 10) -> List[Dict[str, Any]]:
        """Load relationship models for other agents."""
        relationships = self._storage.get_relationships()

        # Sort by last interaction, descending
        relationships = sorted(
            relationships,
            key=lambda r: r.last_interaction or datetime.min.replace(tzinfo=timezone.utc),
            reverse=True,
        )

        return [
            {
                "other_stack_id": r.entity_name,  # backwards compat
                "entity_name": r.entity_name,
                "entity_type": r.entity_type,
                "trust_level": (r.sentiment + 1) / 2,  # Convert sentiment to trust
                "sentiment": r.sentiment,
                "interaction_count": r.interaction_count,
                "last_interaction": r.last_interaction.isoformat() if r.last_interaction else None,
                "notes": r.notes,
            }
            for r in relationships[:limit]
        ]

    def get_relationship_history(
        self,
        entity_name: str,
        event_type: Optional[str] = None,
        limit: int = 50,
    ) -> List[Dict[str, Any]]:
        """Get the history of changes for a relationship.

        Args:
            entity_name: Name of the entity
            event_type: Filter by event type (interaction, trust_change, type_change, note)
            limit: Maximum entries to return

        Returns:
            List of history entries as dicts
        """
        entries = self._storage.get_relationship_history(
            entity_name, event_type=event_type, limit=limit
        )
        return [
            {
                "id": e.id,
                "relationship_id": e.relationship_id,
                "entity_name": e.entity_name,
                "event_type": e.event_type,
                "old_value": e.old_value,
                "new_value": e.new_value,
                "episode_id": e.episode_id,
                "notes": e.notes,
                "created_at": e.created_at.isoformat() if e.created_at else None,
            }
            for e in entries
        ]

    # =========================================================================
    # ENTITY MODELS (Mental Models of Other Entities)
    # =========================================================================

    def add_entity_model(
        self,
        entity_name: str,
        model_type: str,
        observation: str,
        confidence: float = 0.7,
        source_episodes: Optional[List[str]] = None,
    ) -> str:
        """Add a mental model observation about an entity.

        Args:
            entity_name: The entity this model is about
            model_type: Type of model (behavioral, preference, capability)
            observation: The observation/model content
            confidence: Confidence in the observation (0.0-1.0)
            source_episodes: Episode IDs supporting this observation

        Returns:
            The entity model ID
        """
        from kernle.storage.base import EntityModel

        entity_name = self._validate_string_input(entity_name, "entity_name", 200)
        observation = self._validate_string_input(observation, "observation", 2000)

        if model_type not in ("behavioral", "preference", "capability"):
            raise ValueError(
                f"Invalid model_type '{model_type}'. "
                "Must be one of: behavioral, preference, capability"
            )

        confidence = max(0.0, min(1.0, confidence))

        model_id = str(uuid.uuid4())
        now = datetime.now(timezone.utc)

        model = EntityModel(
            id=model_id,
            stack_id=self.stack_id,
            entity_name=entity_name,
            model_type=model_type,
            observation=observation,
            confidence=confidence,
            source_episodes=source_episodes,
            created_at=now,
            updated_at=now,
            subject_ids=[entity_name],  # Auto-populate
        )

        self._storage.save_entity_model(model)
        return model_id

    def get_entity_models(
        self,
        entity_name: Optional[str] = None,
        model_type: Optional[str] = None,
        limit: int = 100,
    ) -> List[Dict[str, Any]]:
        """Get entity models, optionally filtered.

        Args:
            entity_name: Filter by entity name
            model_type: Filter by model type
            limit: Maximum models to return

        Returns:
            List of entity models as dicts
        """
        models = self._storage.get_entity_models(
            entity_name=entity_name, model_type=model_type, limit=limit
        )
        return [
            {
                "id": m.id,
                "entity_name": m.entity_name,
                "model_type": m.model_type,
                "observation": m.observation,
                "confidence": m.confidence,
                "source_episodes": m.source_episodes,
                "created_at": m.created_at.isoformat() if m.created_at else None,
                "updated_at": m.updated_at.isoformat() if m.updated_at else None,
            }
            for m in models
        ]

    def get_entity_model(self, model_id: str) -> Optional[Dict[str, Any]]:
        """Get a specific entity model by ID.

        Args:
            model_id: ID of the entity model

        Returns:
            Entity model as dict or None if not found
        """
        m = self._storage.get_entity_model(model_id)
        if not m:
            return None
        return {
            "id": m.id,
            "entity_name": m.entity_name,
            "model_type": m.model_type,
            "observation": m.observation,
            "confidence": m.confidence,
            "source_episodes": m.source_episodes,
            "created_at": m.created_at.isoformat() if m.created_at else None,
            "updated_at": m.updated_at.isoformat() if m.updated_at else None,
        }

    # =========================================================================
    # TEMPORAL MEMORY (Time-Aware Retrieval)
    # =========================================================================

    def load_temporal(
        self,
        start: Optional[datetime] = None,
        end: Optional[datetime] = None,
        limit: int = 20,
    ) -> Dict[str, Any]:
        """Load memories within a time range."""
        if end is None:
            end = datetime.now(timezone.utc)
        if start is None:
            start = end.replace(hour=0, minute=0, second=0, microsecond=0)

        # Get episodes in range
        episodes = self._storage.get_episodes(limit=limit, since=start)
        episodes = [e for e in episodes if e.created_at and e.created_at <= end]

        # Get notes in range
        notes = self._storage.get_notes(limit=limit, since=start)
        notes = [n for n in notes if n.created_at and n.created_at <= end]

        return {
            "range": {"start": start.isoformat(), "end": end.isoformat()},
            "episodes": [
                {
                    "objective": e.objective,
                    "outcome_type": e.outcome_type,
                    "lessons_learned": e.lessons,
                    "created_at": e.created_at.isoformat() if e.created_at else None,
                }
                for e in episodes
            ],
            "notes": [
                {
                    "content": n.content,
                    "metadata": {"note_type": n.note_type, "tags": n.tags},
                    "created_at": n.created_at.isoformat() if n.created_at else None,
                }
                for n in notes
            ],
        }

    def what_happened(self, when: str = "today") -> Dict[str, Any]:
        """Natural language time query."""
        now = datetime.now(timezone.utc)

        if when == "today":
            start = now.replace(hour=0, minute=0, second=0, microsecond=0)
        elif when == "yesterday":
            start = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=1)
            end = now.replace(hour=0, minute=0, second=0, microsecond=0)
            return self.load_temporal(start, end)
        elif when == "this week":
            start = now - timedelta(days=now.weekday())
            start = start.replace(hour=0, minute=0, second=0, microsecond=0)
        elif when == "last hour":
            start = now - timedelta(hours=1)
        else:
            # Default to today
            start = now.replace(hour=0, minute=0, second=0, microsecond=0)

        return self.load_temporal(start, now)

    # =========================================================================
    # SIGNAL DETECTION (Auto-Capture Significance)
    # =========================================================================

    SIGNAL_PATTERNS = {
        "success": {
            "keywords": ["completed", "done", "finished", "succeeded", "works", "fixed", "solved"],
            "weight": 0.7,
            "type": "positive",
        },
        "failure": {
            "keywords": ["failed", "error", "broken", "doesn't work", "bug", "issue"],
            "weight": 0.7,
            "type": "negative",
        },
        "decision": {
            "keywords": ["decided", "chose", "going with", "will use", "picked"],
            "weight": 0.8,
            "type": "decision",
        },
        "lesson": {
            "keywords": ["learned", "realized", "insight", "discovered", "understood"],
            "weight": 0.9,
            "type": "lesson",
        },
        "feedback": {
            "keywords": ["great", "thanks", "helpful", "perfect", "exactly", "wrong", "not what"],
            "weight": 0.6,
            "type": "feedback",
        },
    }

    def detect_significance(self, text: str) -> Dict[str, Any]:
        """Detect if text contains significant signals worth capturing."""
        text_lower = text.lower()
        signals = []
        total_weight = 0.0

        for signal_name, pattern in self.SIGNAL_PATTERNS.items():
            for keyword in pattern["keywords"]:
                if keyword in text_lower:
                    signals.append(
                        {
                            "signal": signal_name,
                            "type": pattern["type"],
                            "weight": pattern["weight"],
                        }
                    )
                    total_weight = max(total_weight, pattern["weight"])
                    break  # One match per pattern is enough

        return {
            "significant": total_weight >= 0.6,
            "score": total_weight,
            "signals": signals,
        }

    def auto_capture(self, text: str, context: Optional[str] = None) -> Optional[str]:
        """Automatically capture text if it's significant."""
        detection = self.detect_significance(text)

        if detection["significant"]:
            # Determine what type of capture
            primary_signal = detection["signals"][0] if detection["signals"] else None

            if primary_signal:
                if primary_signal["type"] == "decision":
                    return self.note(text, type="decision", tags=["auto-captured"])
                elif primary_signal["type"] == "lesson":
                    return self.note(text, type="insight", tags=["auto-captured"])
                elif primary_signal["type"] in ("positive", "negative"):
                    # Could be an episode outcome
                    outcome = "success" if primary_signal["type"] == "positive" else "partial"
                    return self.episode(
                        objective=context or "Auto-captured event",
                        outcome=outcome,
                        lessons=[text] if "learn" in text.lower() else None,
                        tags=["auto-captured"],
                    )
                else:
                    return self.note(text, type="note", tags=["auto-captured"])

        return None

    # =========================================================================
    # SEARCH
    # =========================================================================

    def search(
        self, query: str, limit: int = 10, min_score: float = None, track_access: bool = True
    ) -> List[Dict[str, Any]]:
        """Search across episodes, notes, and beliefs.

        Args:
            query: Search query string
            limit: Maximum results to return
            min_score: Minimum similarity score (0.0-1.0) to include in results.
                       If None, returns all results up to limit.
            track_access: If True (default), record access for salience tracking.
        """
        # Request more results if filtering by score
        fetch_limit = limit * 3 if min_score else limit
        results = self._storage.search(query, limit=fetch_limit)

        # Filter by minimum score if specified
        if min_score is not None:
            results = [r for r in results if r.score >= min_score]

        # Track access for returned results
        if track_access and results:
            accesses = [(r.record_type, r.record.id) for r in results[:limit]]
            self._storage.record_access_batch(accesses)

        formatted = []
        for r in results:
            record = r.record
            record_type = r.record_type

            if record_type == "episode":
                formatted.append(
                    {
                        "type": "episode",
                        "title": record.objective[:60] if record.objective else "",
                        "content": record.outcome,
                        "lessons": (record.lessons or [])[:2],
                        "date": record.created_at.strftime("%Y-%m-%d") if record.created_at else "",
                    }
                )
            elif record_type == "note":
                formatted.append(
                    {
                        "type": record.note_type or "note",
                        "title": record.content[:60] if record.content else "",
                        "content": record.content,
                        "tags": record.tags or [],
                        "date": record.created_at.strftime("%Y-%m-%d") if record.created_at else "",
                    }
                )
            elif record_type == "belief":
                formatted.append(
                    {
                        "type": "belief",
                        "title": record.statement[:60] if record.statement else "",
                        "content": record.statement,
                        "confidence": record.confidence,
                        "date": record.created_at.strftime("%Y-%m-%d") if record.created_at else "",
                    }
                )

        return formatted[:limit]

    # =========================================================================
    # STATUS
    # =========================================================================

    def status(self) -> Dict[str, Any]:
        """Get memory statistics."""
        stats = self._storage.get_stats()

        return {
            "stack_id": self.stack_id,
            "values": stats.get("values", 0),
            "beliefs": stats.get("beliefs", 0),
            "goals": stats.get("goals", 0),
            "episodes": stats.get("episodes", 0),
            "raw": stats.get("raw", 0),
            "checkpoint": self.load_checkpoint() is not None,
        }

    # =========================================================================
    # FORMATTING
    # =========================================================================

    def format_memory(self, memory: Optional[Dict[str, Any]] = None) -> str:
        """Format memory for injection into context."""
        if memory is None:
            memory = self.load()

        lines = [
            f"# Working Memory ({self.stack_id})",
            f"_Loaded at {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}_",
            "",
            "<!-- USAGE: This is your persistent memory. Resume work from 'Continue With' ",
            "section without announcing recovery. Save checkpoints with specific task ",
            "descriptions before breaks or when context pressure builds. -->",
            "",
        ]

        # Boot config - always first (pre-load config)
        if memory.get("boot_config"):
            lines.append("## Boot Config")
            for k, v in sorted(memory["boot_config"].items()):
                lines.append(f"- {k}: {v}")
            lines.append("")

        # Checkpoint - prominently displayed at top with directive language
        if memory.get("checkpoint"):
            cp = memory["checkpoint"]

            # Calculate checkpoint age
            age_warning = ""
            try:
                ts = cp.get("timestamp", "")
                if ts:
                    cp_time = datetime.fromisoformat(ts.replace("Z", "+00:00"))
                    now = datetime.now(timezone.utc)
                    age = now - cp_time
                    if age.total_seconds() > 24 * 3600:
                        age_warning = f"\n⚠ _Checkpoint is {age.days}+ days old - may be stale_"
                    elif age.total_seconds() > 6 * 3600:
                        age_warning = f"\n⚠ _Checkpoint is {age.seconds // 3600}+ hours old_"
            except Exception as e:
                logger.debug(f"Failed to parse checkpoint age: {e}")

            lines.append("## Continue With")
            lines.append(f"**Current task**: {cp.get('current_task', 'unknown')}")
            if cp.get("context"):
                lines.append(f"**Context**: {cp['context']}")
            if cp.get("pending"):
                lines.append("**Next steps**:")
                for p in cp["pending"]:
                    lines.append(f"  - {p}")
            if age_warning:
                lines.append(age_warning)
            lines.append("")
            # Add directive for seamless continuation
            lines.append("_Resume this work naturally. Don't announce recovery or ask what to do._")
            lines.append("")

        # Values
        if memory.get("values"):
            lines.append("## Values")
            for v in memory["values"]:
                lines.append(f"- **{v['name']}**: {v['statement']}")
            lines.append("")

        # Goals
        if memory.get("goals"):
            lines.append("## Goals")
            for g in memory["goals"]:
                priority = f" [{g['priority']}]" if g.get("priority") else ""
                lines.append(f"- {g['title']}{priority}")
            lines.append("")

        # Beliefs
        if memory.get("beliefs"):
            lines.append("## Beliefs")
            for b in memory["beliefs"]:
                conf = f" ({b['confidence']})" if b.get("confidence") else ""
                lines.append(f"- {b['statement']}{conf}")
            lines.append("")

        # Lessons
        if memory.get("lessons"):
            lines.append("## Lessons")
            for lesson in memory["lessons"][:10]:
                lines.append(f"- {lesson}")
            lines.append("")

        # Recent work
        if memory.get("recent_work"):
            lines.append("## Recent Work")
            for w in memory["recent_work"][:3]:
                lines.append(f"- {w['objective']} [{w.get('outcome_type', '?')}]")
            lines.append("")

        # Drives
        if memory.get("drives"):
            lines.append("## Drives")
            for d in memory["drives"]:
                lines.append(f"- **{d['drive_type']}**: {d['intensity']:.0%}")
            lines.append("")

        # Relationships
        if memory.get("relationships"):
            lines.append("## Key Relationships")
            for r in memory["relationships"][:5]:
                lines.append(f"- {r['entity_name']}: sentiment {r.get('sentiment', 0):.0%}")
            lines.append("")

        # Footer with checkpoint guidance
        lines.append("---")
        lines.append(
            f'_Save state: `kernle -s {self.stack_id} checkpoint "<specific task>"` '
            "before breaks or context pressure._"
        )

        return "\n".join(lines)
