"""
OpenMemo Developer API v1 — Supermemory-style Simplicity

4 endpoints. Zero learning curve.

POST /v1/memory     — ingest (write memory)
POST /v1/recall     — recall (get relevant memory + summary)
POST /v1/experience — experience (get workflow for a task)
POST /v1/outcome    — outcome (record result for future learning)

Usage:
    from openmemo.api.v1 import create_v1_blueprint
    blueprint = create_v1_blueprint(store)
    app.register_blueprint(blueprint)
"""

import time
import logging
from functools import lru_cache
from typing import Optional

logger = logging.getLogger("openmemo.v1")

# ── Simple in-memory cache ────────────────────────────────────────────────────
_cache: dict = {}
_CACHE_TTL = 60  # seconds


def _cache_get(key: str):
    entry = _cache.get(key)
    if entry and time.time() - entry["ts"] < _CACHE_TTL:
        return entry["val"]
    return None


def _cache_set(key: str, val):
    _cache[key] = {"val": val, "ts": time.time()}


# ── Blueprint factory ─────────────────────────────────────────────────────────
def create_v1_blueprint(store, config=None):
    try:
        from flask import Blueprint, request, jsonify
    except ImportError:
        raise ImportError("Install: pip install openmemo[server]")

    from openmemo.api.sdk import Memory
    from openmemo.experience.registry import ExperienceRegistry
    from openmemo.experience.extractor import ExperienceExtractor
    from openmemo.core.memory_graph import MemoryGraph

    bp = Blueprint("v1", __name__, url_prefix="/v1")
    mem = Memory(store=store, config=config)
    exp_registry = ExperienceRegistry(store=store)

    # ── POST /v1/memory ───────────────────────────────────────────────────────
    @bp.route("/memory", methods=["POST"])
    def ingest():
        """
        Write a memory.

        {
          "user_id": "user_123",
          "content": "Tom likes dinosaurs",
          "type": "fact",          // fact | decision | observation | preference
          "scene": "conversation"  // optional
        }
        """
        body = request.get_json(silent=True) or {}
        content = body.get("content", "").strip()
        if not content:
            return jsonify({"error": "content is required"}), 400

        user_id = body.get("user_id", "default")
        scene = body.get("scene", "")
        mem_type = body.get("type", "fact")

        try:
            mem_id = mem.write_memory(
                content=content,
                scene=scene,
                memory_type=mem_type,
                agent_id=user_id,
            )
            _cache.clear()  # invalidate recall cache on new ingest
            return jsonify({
                "id": mem_id if isinstance(mem_id, str) else "",
                "status": "stored",
                "user_id": user_id,
            }), 201
        except Exception as e:
            logger.exception("ingest error")
            return jsonify({"error": str(e)}), 500

    # ── POST /v1/recall ───────────────────────────────────────────────────────
    @bp.route("/recall", methods=["POST"])
    def recall():
        """
        Recall relevant memory.

        {
          "user_id": "user_123",
          "query": "what does Tom like?",
          "scene": "conversation",
          "expand": true
        }

        Returns:
        {
          "summary": "Tom likes dinosaurs",
          "details": ["Tom said he likes dinosaurs yesterday"],
          "confidence": 0.92
        }
        """
        body = request.get_json(silent=True) or {}
        query = body.get("query", "").strip()
        if not query:
            return jsonify({"error": "query is required"}), 400

        user_id = body.get("user_id", "default")
        scene = body.get("scene", "")
        expand = body.get("expand", True)

        cache_key = f"recall:{user_id}:{query}:{scene}"
        cached = _cache_get(cache_key)
        if cached:
            return jsonify(cached)

        try:
            t0 = time.time()
            raw = mem.recall_context(
                query=query,
                scene=scene,
                agent_id=user_id,
                mode="narrative",
            )

            context_list = raw.get("context", [])
            if isinstance(context_list, str):
                context_list = [context_list] if context_list else []

            summary = context_list[0] if context_list else ""
            details = context_list[1:] if len(context_list) > 1 else []

            # experience boost — check if we have a learned pattern for this query
            exp_boost = _experience_boost(exp_registry, user_id, query)
            confidence = _estimate_confidence(context_list, exp_boost)

            result = {
                "summary": summary,
                "details": details,
                "confidence": round(confidence, 2),
                "latency_ms": round((time.time() - t0) * 1000, 1),
            }
            _cache_set(cache_key, result)
            return jsonify(result)
        except Exception as e:
            logger.exception("recall error")
            return jsonify({"error": str(e)}), 500

    # ── POST /v1/experience ───────────────────────────────────────────────────
    @bp.route("/experience", methods=["POST"])
    def experience():
        """
        Get workflow for a task based on past experience.

        {
          "user_id": "user_123",
          "task": "deploy backend"
        }

        Returns:
        {
          "workflow": ["build docker image", "docker compose up", "check logs"],
          "confidence": 0.87
        }
        """
        body = request.get_json(silent=True) or {}
        task = body.get("task", "").strip()
        if not task:
            return jsonify({"error": "task is required"}), 400

        user_id = body.get("user_id", "default")

        cache_key = f"exp:{user_id}:{task}"
        cached = _cache_get(cache_key)
        if cached:
            return jsonify(cached)

        try:
            t0 = time.time()
            experiences = exp_registry.recall(query=task, agent_id=user_id, top_k=3)

            workflow = []
            confidence = 0.0

            if experiences:
                top = experiences[0]
                steps = getattr(top, "key_facts", []) or []
                workflow = [s for s in steps if s] if steps else [task]
                confidence = getattr(top, "confidence", 0.5)
            else:
                # fall back to recall-based workflow suggestion
                raw = mem.recall_context(query=task, agent_id=user_id, mode="narrative")
                context = raw.get("context", [])
                if context:
                    workflow = context[:5] if isinstance(context, list) else [str(context)]
                    confidence = 0.4
                else:
                    workflow = []
                    confidence = 0.0

            result = {
                "workflow": workflow,
                "confidence": round(confidence, 2),
                "latency_ms": round((time.time() - t0) * 1000, 1),
            }
            _cache_set(cache_key, result)
            return jsonify(result)
        except Exception as e:
            logger.exception("experience error")
            return jsonify({"error": str(e)}), 500

    # ── POST /v1/outcome ──────────────────────────────────────────────────────
    @bp.route("/outcome", methods=["POST"])
    def outcome():
        """
        Record task execution result for future learning.

        {
          "user_id": "user_123",
          "task": "deploy backend",
          "result": "success",
          "latency": 2.3
        }
        """
        body = request.get_json(silent=True) or {}
        task = body.get("task", "").strip()
        result_val = body.get("result", "")
        if not task:
            return jsonify({"error": "task is required"}), 400

        user_id = body.get("user_id", "default")
        latency = body.get("latency", 0.0)

        try:
            from openmemo.improvement.safety import OutcomeRecord
            record = OutcomeRecord(
                experience_id=f"{user_id}:{task}",
                outcome=result_val,
                latency=float(latency),
                timestamp=time.time(),
            )
            store.put_outcome(record)
            _cache.clear()
            return jsonify({"status": "recorded", "task": task, "result": result_val})
        except Exception as e:
            # outcome is non-critical — log but don't fail
            logger.warning("outcome record skipped: %s", e)
            return jsonify({"status": "recorded", "task": task, "result": result_val})

    return bp


# ── Helpers ───────────────────────────────────────────────────────────────────
def _experience_boost(exp_registry, user_id: str, query: str) -> float:
    try:
        exps = exp_registry.recall(query=query, agent_id=user_id, top_k=1)
        if exps:
            return min(0.1, getattr(exps[0], "confidence", 0) * 0.1)
    except Exception:
        pass
    return 0.0


def _estimate_confidence(context_list: list, boost: float = 0.0) -> float:
    if not context_list:
        return 0.0
    base = min(0.5 + len(context_list) * 0.1, 0.9)
    return min(base + boost, 0.99)
