"""
Experience + WorkflowTemplate data models — Phase 23.6

Experience:
    Structured narrative of what an agent learned from a sequence of
    memory events. Sits above DAG summary nodes in the memory hierarchy.

    Raw → Summary (Phase 23.5) → Experience (Phase 23.6)

WorkflowTemplate:
    Actionable, reusable step sequence derived from an Experience.
    "Next time you encounter X, do Y, Z, W in this order."
"""

import json
import time
import uuid
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional


EXPERIENCE_TYPES = {
    "workflow",     # multi-step process learned from execution
    "lesson",       # what went wrong and why
    "pattern",      # repeating behavior across tasks
    "decision",     # key decision and its outcome
    "insight",      # cross-domain generalization
}


@dataclass
class Experience:
    """
    A single experience extracted from memory nodes.

    Fields:
        id              — unique ID (exp_<hex>)
        title           — short description
        type            — experience type (workflow/lesson/pattern/decision/insight)
        source_node_ids — DAG memory nodes this was extracted from
        steps           — ordered list of action steps observed
        outcome         — what was the final result/outcome
        key_facts       — bullet-point learnings
        conditions      — when this experience applies {trigger, scene, context}
        confidence      — 0.0–1.0
        scene           — memory scene/domain
        agent_id        — agent that generated this experience
        created_at      — unix timestamp
        usage_count     — how many times recalled/applied
        metadata        — arbitrary extra fields
    """
    id: str = field(default_factory=lambda: f"exp_{uuid.uuid4().hex[:12]}")
    title: str = ""
    type: str = "workflow"
    source_node_ids: List[str] = field(default_factory=list)
    steps: List[str] = field(default_factory=list)
    outcome: str = ""
    key_facts: List[str] = field(default_factory=list)
    conditions: Dict[str, Any] = field(default_factory=dict)
    confidence: float = 0.7
    scene: str = ""
    agent_id: str = ""
    created_at: float = field(default_factory=time.time)
    usage_count: int = 0
    metadata: Dict[str, Any] = field(default_factory=dict)

    def __post_init__(self):
        if self.type not in EXPERIENCE_TYPES:
            self.type = "workflow"
        self.confidence = max(0.0, min(1.0, float(self.confidence)))

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "title": self.title,
            "type": self.type,
            "source_node_ids": self.source_node_ids,
            "steps": self.steps,
            "outcome": self.outcome,
            "key_facts": self.key_facts,
            "conditions": self.conditions,
            "confidence": self.confidence,
            "scene": self.scene,
            "agent_id": self.agent_id,
            "created_at": self.created_at,
            "usage_count": self.usage_count,
            "metadata": self.metadata,
        }

    @classmethod
    def from_dict(cls, d: dict) -> "Experience":
        def _loads(v, default):
            if isinstance(v, str):
                try:
                    return json.loads(v)
                except Exception:
                    return default
            return v if v is not None else default

        return cls(
            id=d.get("id", f"exp_{uuid.uuid4().hex[:12]}"),
            title=d.get("title", ""),
            type=d.get("type", "workflow"),
            source_node_ids=_loads(d.get("source_node_ids", []), []),
            steps=_loads(d.get("steps", []), []),
            outcome=d.get("outcome", ""),
            key_facts=_loads(d.get("key_facts", []), []),
            conditions=_loads(d.get("conditions", {}), {}),
            confidence=float(d.get("confidence", 0.7)),
            scene=d.get("scene", ""),
            agent_id=d.get("agent_id", ""),
            created_at=float(d.get("created_at", time.time())),
            usage_count=int(d.get("usage_count", 0)),
            metadata=_loads(d.get("metadata", {}), {}),
        )

    def to_prompt_text(self) -> str:
        """Format experience for prompt injection."""
        lines = [f"[Experience: {self.title}]"]
        if self.steps:
            lines.append("Steps:")
            for i, s in enumerate(self.steps, 1):
                lines.append(f"  {i}. {s}")
        if self.outcome:
            lines.append(f"Outcome: {self.outcome}")
        if self.key_facts:
            lines.append("Key learnings:")
            for f in self.key_facts:
                lines.append(f"  - {f}")
        return "\n".join(lines)


@dataclass
class WorkflowTemplate:
    """
    A reusable workflow template derived from an Experience.

    Fields:
        id              — unique ID (wf_<hex>)
        name            — workflow name
        trigger         — when to apply this workflow (description)
        steps           — list of {step, tool, input_template, condition}
        experience_id   — source experience ID
        scene           — applicable scene
        agent_id        — agent that generated this
        success_rate    — 0.0–1.0 (updated on execution feedback)
        usage_count     — how many times executed
        created_at      — unix timestamp
        metadata        — extra fields
    """
    id: str = field(default_factory=lambda: f"wf_{uuid.uuid4().hex[:12]}")
    name: str = ""
    trigger: str = ""
    steps: List[Dict[str, Any]] = field(default_factory=list)
    experience_id: str = ""
    scene: str = ""
    agent_id: str = ""
    success_rate: float = 0.0
    usage_count: int = 0
    created_at: float = field(default_factory=time.time)
    metadata: Dict[str, Any] = field(default_factory=dict)

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "trigger": self.trigger,
            "steps": self.steps,
            "experience_id": self.experience_id,
            "scene": self.scene,
            "agent_id": self.agent_id,
            "success_rate": self.success_rate,
            "usage_count": self.usage_count,
            "created_at": self.created_at,
            "metadata": self.metadata,
        }

    @classmethod
    def from_dict(cls, d: dict) -> "WorkflowTemplate":
        def _loads(v, default):
            if isinstance(v, str):
                try:
                    return json.loads(v)
                except Exception:
                    return default
            return v if v is not None else default

        return cls(
            id=d.get("id", f"wf_{uuid.uuid4().hex[:12]}"),
            name=d.get("name", ""),
            trigger=d.get("trigger", ""),
            steps=_loads(d.get("steps", []), []),
            experience_id=d.get("experience_id", ""),
            scene=d.get("scene", ""),
            agent_id=d.get("agent_id", ""),
            success_rate=float(d.get("success_rate", 0.0)),
            usage_count=int(d.get("usage_count", 0)),
            created_at=float(d.get("created_at", time.time())),
            metadata=_loads(d.get("metadata", {}), {}),
        )

    def to_prompt_text(self) -> str:
        """Format workflow for prompt injection."""
        lines = [f"[Workflow: {self.name}]",
                 f"Trigger: {self.trigger}",
                 "Steps:"]
        for i, step in enumerate(self.steps, 1):
            s = step.get("step", step) if isinstance(step, dict) else step
            tool = step.get("tool", "") if isinstance(step, dict) else ""
            if tool:
                lines.append(f"  {i}. {s} (tool: {tool})")
            else:
                lines.append(f"  {i}. {s}")
        return "\n".join(lines)
