"""
OpenMemo User Memory Layer

Lightweight user memory for experience optimization.
PRD: v1.0 — preference / constraint / environment memory

    from openmemo.user_memory import UserMemory

    um = UserMemory("openmemo.db")
    um.store("alice", "Use docker-compose instead of Kubernetes")
    prompt_block = um.format_for_prompt("alice")
    ranked = um.rank_workflows("alice", workflows)
"""

from openmemo.user_memory.user_memory_store import UserMemoryStore, UserMemoryNode
from openmemo.user_memory.user_memory_extractor import UserMemoryExtractor
from openmemo.user_memory.user_memory_recall import UserMemoryRecall
from openmemo.user_memory.user_memory_ranker import UserMemoryRanker


class UserMemory:
    """
    Unified facade for the User Memory Layer.

    Combines Store + Extractor + Recall + Ranker into one interface.

    Usage:
        um = UserMemory("openmemo.db")

        # Auto-extract from text and store
        um.store("alice", "I prefer FastAPI and avoid Kubernetes")

        # Manually store a node
        um.put("alice", "preference", "backend", "FastAPI", confidence=0.95)

        # Recall as prompt block
        block = um.format_for_prompt("alice")

        # Rank workflows by user alignment
        ranked = um.rank_workflows("alice", [
            {"id": "wf1", "steps": ["docker-compose up"], "score": 0.8},
            {"id": "wf2", "steps": ["kubectl apply"], "score": 0.75},
        ])
    """

    def __init__(self, db_path: str = "openmemo.db"):
        self.db_path = db_path
        self._store = UserMemoryStore(db_path=db_path)
        self._extractor = UserMemoryExtractor()
        self._recall = UserMemoryRecall(self._store)
        self._ranker = UserMemoryRanker(self._store)

    # ── Write ──────────────────────────────────────────────────────────────────

    def store(self, user_id: str, text: str) -> list:
        """
        Auto-extract user memories from free text and persist them.

        Returns list of stored memory_ids.
        """
        nodes = self._extractor.extract(user_id, text)
        ids = []
        for node in nodes:
            mid = self._store.put(node)
            ids.append(mid)
        return ids

    def put(
        self,
        user_id: str,
        mem_type: str,
        key: str,
        value: str,
        confidence: float = 0.9,
        source: str = "user_explicit",
    ) -> str:
        """
        Explicitly store a user memory node.

        mem_type: "preference" | "constraint" | "environment" | "behavior"
        """
        node = UserMemoryNode(
            user_id=user_id,
            type=mem_type,
            key=key,
            value=value,
            confidence=confidence,
            source=source,
        )
        return self._store.put(node)

    # ── Read ───────────────────────────────────────────────────────────────────

    def recall(self, user_id: str, top_n: int = 5) -> list:
        """Return top-N ranked UserMemoryNodes for a user."""
        return self._recall.recall(user_id, top_n=top_n)

    def format_for_prompt(self, user_id: str, top_n: int = 5) -> str:
        """
        Return a USER PROFILE prompt block for injection before TEAM CONTEXT.

        Example output:
            USER PROFILE
            User Preferences:
              - prefers FastAPI
              - prefers docker-compose
            Constraints:
              - avoid Kubernetes
        """
        return self._recall.format_for_prompt(user_id, top_n=top_n)

    def to_dict(self, user_id: str, top_n: int = 5) -> dict:
        """Return structured dict for API response."""
        return self._recall.to_dict(user_id, top_n=top_n)

    # ── Rank ───────────────────────────────────────────────────────────────────

    def rank_workflows(
        self,
        user_id: str,
        workflows: list,
        score_key: str = "score",
    ) -> list:
        """
        Re-rank a list of workflow dicts using user alignment.

        Each workflow dict must have a score field (0-1).
        Returns workflows sorted by final_score (descending).

        final_score = workflow_score*0.7 + user_alignment_score*0.3
        """
        return self._ranker.rank_workflows(user_id, workflows, score_key)

    def alignment_score(self, user_id: str, workflow_text: str) -> float:
        """Compute alignment score (0-1) for a workflow description string."""
        return self._ranker.compute_alignment(user_id, workflow_text)

    # ── Admin ──────────────────────────────────────────────────────────────────

    def delete(self, memory_id: str) -> bool:
        """Delete a specific user memory node."""
        return self._store.delete(memory_id)

    def delete_user(self, user_id: str) -> int:
        """Delete all memory for a user. Returns count deleted."""
        return self._store.delete_by_user(user_id)

    def count(self, user_id: str) -> int:
        """Return total memory count for a user."""
        return self._store.count(user_id)

    def close(self):
        self._store.close()


__all__ = [
    "UserMemory",
    "UserMemoryStore",
    "UserMemoryNode",
    "UserMemoryExtractor",
    "UserMemoryRecall",
    "UserMemoryRanker",
]
