"""
OpenMemo Memory Feedback Loop

Self-optimization layer for the memory system.
Tracks which memories are useful and adjusts rankings accordingly.

PRD §22: "Memory Feedback Loop lets OpenMemo evolve from 'has memory'
          to 'optimizes memory'."

    from openmemo.memory_feedback import MemoryFeedback

    fb = MemoryFeedback("openmemo.db")

    # On recall
    fb.on_recall(["mem_1", "mem_2"], task_id="t1", agent_id="claw")

    # On inject
    fb.on_inject("mem_1", task_id="t1", token_size=120, position="experience_block")

    # On adoption detected
    fb.on_adopt(task_id="t1", memory_id="mem_1", adopted=True,
                 workflow_id="wf_1", adoption_rate=0.8)

    # On task complete
    fb.on_outcome(task_id="t1", memory_ids=["mem_1"],
                   workflow_id="wf_1", success=True)

    # Adjust recall rankings
    ranked = fb.adjust_recall(results)

    # Get memory quality
    profile = fb.get_quality_profile("mem_1")
    print(profile.quality_score)   # e.g. 0.78
"""

from openmemo.memory_feedback.feedback_store import (
    FeedbackStore, MemoryFeedbackRecord, WorkflowFeedbackRecord,
    MemoryQualityProfile
)
from openmemo.memory_feedback.quality_scorer import QualityScorer, recency_score
from openmemo.memory_feedback.feedback_collector import FeedbackCollector
from openmemo.memory_feedback.ranking_adjuster import RankingAdjuster
from openmemo.memory_feedback.workflow_feedback import WorkflowFeedback


class MemoryFeedback:
    """
    Unified facade for the Memory Feedback Loop.

    Wires together Store + Collector + Scorer + Adjuster + WorkflowFeedback.
    """

    def __init__(self, db_path: str = "openmemo.db"):
        self._store = FeedbackStore(db_path=db_path)
        self._scorer = QualityScorer(self._store)
        self._collector = FeedbackCollector(self._store, self._scorer)
        self._adjuster = RankingAdjuster(self._store, self._scorer)
        self._workflow = WorkflowFeedback(self._store, self._scorer)

    # ── Signal Collection (PRD §12) ────────────────────────────────────────────

    def on_recall(self, memory_ids: list, task_id: str = "",
                   agent_id: str = "", memory_layer: str = "") -> list:
        """§12.1 — Record recall signal."""
        return self._collector.on_recall(memory_ids, task_id=task_id,
                                          agent_id=agent_id,
                                          memory_layer=memory_layer)

    def on_inject(self, memory_id: str, task_id: str = "",
                   token_size: int = 0, position: str = "",
                   agent_id: str = "") -> str:
        """§12.2 — Record injection signal."""
        return self._collector.on_inject(memory_id, task_id=task_id,
                                          token_size=token_size,
                                          position=position, agent_id=agent_id)

    def on_adopt(self, task_id: str, memory_id: str = "",
                  workflow_id: str = "", adopted: bool = False,
                  adoption_rate: float = 0.0, agent_id: str = "") -> str:
        """§12.3 — Record adoption signal."""
        return self._collector.on_adopt(task_id, memory_id=memory_id,
                                         workflow_id=workflow_id,
                                         adopted=adopted,
                                         adoption_rate=adoption_rate,
                                         agent_id=agent_id)

    def on_outcome(self, task_id: str, success: bool = False,
                    memory_ids: list = None, workflow_id: str = "",
                    execution_time: float = 0.0, agent_id: str = "") -> list:
        """§12.4 — Record outcome signal."""
        return self._collector.on_outcome(task_id, success=success,
                                           memory_ids=memory_ids,
                                           workflow_id=workflow_id,
                                           execution_time=execution_time,
                                           agent_id=agent_id)

    # ── Ranking Adjustment (PRD §10) ───────────────────────────────────────────

    def adjust_recall(self, results: list, id_key: str = "id",
                       score_key: str = "score") -> list:
        """§10.1 — Re-rank recall results using quality scores."""
        return self._adjuster.adjust_recall(results, id_key=id_key,
                                             score_key=score_key)

    def adjust_workflows(self, workflows: list, id_key: str = "id",
                          score_key: str = "score") -> list:
        """§10.2 — Re-rank workflow recommendations."""
        return self._adjuster.adjust_workflows(workflows, id_key=id_key,
                                                score_key=score_key)

    # ── Workflow Feedback (PRD §5.2) ───────────────────────────────────────────

    def workflow_recommend(self, workflow_id: str, task_id: str = "",
                            agent_id: str = "") -> str:
        """Record a workflow recommendation."""
        return self._workflow.on_recommend(workflow_id, task_id=task_id,
                                            agent_id=agent_id)

    def workflow_on_step(self, task_id: str, step_text: str,
                          workflow_id: str = "",
                          workflow_steps: list = None) -> dict:
        """Detect workflow adoption from agent step text."""
        return self._workflow.on_step(task_id, step_text,
                                       workflow_id=workflow_id,
                                       workflow_steps=workflow_steps)

    def workflow_on_complete(self, task_id: str, workflow_id: str = "",
                              success: bool = False,
                              execution_time: float = 0.0) -> str:
        """Record workflow outcome."""
        return self._workflow.on_complete(task_id, workflow_id=workflow_id,
                                           success=success,
                                           execution_time=execution_time)

    # ── Quality Queries ────────────────────────────────────────────────────────

    def get_quality_profile(self, memory_id: str) -> MemoryQualityProfile:
        return self._store.get_quality_profile(memory_id)

    def get_quality_score(self, memory_id: str) -> float:
        return self._adjuster.get_quality_score(memory_id)

    def get_workflow_quality(self, workflow_id: str) -> dict:
        return self._scorer.score_workflow(workflow_id)

    def is_suppressed(self, memory_id: str) -> bool:
        return self._adjuster.is_suppressed(memory_id)

    def is_promoted(self, memory_id: str) -> bool:
        return self._adjuster.is_promoted(memory_id)

    def list_noisy_memories(self, min_noise: int = 3) -> list:
        return self._store.list_noisy_profiles(min_noise=min_noise)

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


__all__ = [
    "MemoryFeedback",
    "FeedbackStore", "MemoryFeedbackRecord", "WorkflowFeedbackRecord",
    "MemoryQualityProfile",
    "QualityScorer", "recency_score",
    "FeedbackCollector",
    "RankingAdjuster",
    "WorkflowFeedback",
]
