"""
Policy Engine — the core decision layer.

Given a memory type and the active policy, answers:
  should_store(memory_type) → True / False

Type taxonomy (maps adapter memory types → policy buckets):
  success_task  : task completed successfully
  workflow      : reusable step sequence extracted
  preference    : explicit user preference
  decision      : key decision made by user/agent
  failed        : task/step that failed
  temporary     : intermediate scratchpad / debug step
  noise         : unclear, low-signal, or duplicate
  observation   : raw observation (default: store)
"""

import logging
from typing import Optional, Dict, Any

from openmemo_openclaw.memory_policy.rule_store import RuleStore, DEFAULT_POLICY

logger = logging.getLogger("openmemo_openclaw")

# Maps the raw memory_type strings the adapter emits → policy bucket names
TYPE_MAP: Dict[str, str] = {
    # success bucket
    "success": "success_task",
    "success_task": "success_task",
    "task_complete": "success_task",
    "task_success": "success_task",
    # workflow bucket
    "workflow": "workflow",
    "experience": "workflow",
    "playbook": "workflow",
    "skill": "workflow",
    # preference bucket
    "preference": "preference",
    "user_preference": "preference",
    "constraint": "preference",
    # decision bucket
    "decision": "decision",
    "decision_log": "decision",
    # failed bucket
    "failed": "failed",
    "failure": "failed",
    "error": "failed",
    "failed_attempt": "failed",
    # temporary / noise
    "temporary": "temporary",
    "debug": "temporary",
    "noise": "noise",
    "duplicate": "noise",
    # default
    "observation": "observation",
    "context": "observation",
    "memory": "observation",
}


def _normalize_type(memory_type: str) -> str:
    """Normalize a raw memory type string to a policy bucket."""
    if not memory_type:
        return "observation"
    return TYPE_MAP.get(memory_type.lower().strip(), "observation")


def should_store(memory_type: str,
                 policy: Optional[Dict[str, Any]] = None) -> bool:
    """
    Core predicate: should this memory type be stored given the active policy?

    Returns True (store) or False (ignore).
    Falls back to True for any type not in the ignore list.
    """
    rules = (policy or DEFAULT_POLICY).get("rules", DEFAULT_POLICY["rules"])
    bucket = _normalize_type(memory_type)

    ignore_list = rules.get("ignore", [])
    store_list = rules.get("store", [])

    if bucket in ignore_list:
        logger.debug("[policy] ignore type=%s bucket=%s", memory_type, bucket)
        return False

    if bucket in store_list:
        return True

    # Unlisted types → default to store (safe default)
    return True


class PolicyEngine:
    """
    Stateful policy engine backed by a RuleStore.

    Usage:
        engine = PolicyEngine(rule_store)
        if engine.should_store("failed"):
            client.store(...)
    """

    def __init__(self, rule_store: Optional[RuleStore] = None):
        self._rule_store = rule_store or RuleStore()

    @property
    def current_policy(self) -> Dict[str, Any]:
        return self._rule_store.get_current()

    def should_store(self, memory_type: str) -> bool:
        policy = self._rule_store.get_current()
        result = should_store(memory_type, policy)
        if not result:
            logger.info(
                "[policy] SKIP type=%s mode=%s",
                memory_type,
                policy.get("mode", "smart"),
            )
        return result

    def get_rule_card(self) -> Dict[str, Any]:
        """Return a UI-ready rule card dict for the Activation Panel."""
        policy = self._rule_store.get_current()
        rules = policy["rules"]
        return {
            "mode": policy.get("name", "Smart Memory Mode"),
            "tagline": policy.get("tagline", "We remember what works, not what doesn't."),
            "we_remember": rules.get("store", []),
            "we_ignore": rules.get("ignore", []),
            "updated_at": policy.get("updated_at", 0),
        }
