"""Working Memory (Tier 1) — in-memory store with TTL.

Adapted from Redis-based implementation to use soagila.db.memory_store.
"""

import json
import logging
from datetime import datetime, timezone

from soagila.db.memory_store import (
    store as _ms_store,
    get as _ms_get,
    get_all as _ms_get_all,
    query as _ms_query,
    flush as _ms_flush,
    get_ttl as _ms_get_ttl,
    count as _ms_count,
)
from soagila.db.event_bus import publish_event
from soagila.core.tcmg.memory_models import WorkingMemory

logger = logging.getLogger("soagila.tcmg.working")

CHANNEL = "soagila:metrics"


async def store(session_id: str, memory: WorkingMemory) -> str:
    """Store a working memory with calculated TTL."""
    ttl = memory.calculate_ttl()
    memory.ttl_seconds = ttl

    # Store as dict in memory store
    await _ms_store(session_id, memory.id, memory.model_dump(mode="json"), ttl)

    # Publish event
    event = json.dumps({
        "type": "memory_stored",
        "tier": "working",
        "memory_id": memory.id,
        "user_id": memory.user_id,
        "session_id": session_id,
        "topic": memory.topic_tags[0] if memory.topic_tags else "general",
        "importance": memory.importance,
        "ttl": ttl,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    })
    await publish_event(CHANNEL, event)

    logger.debug(f"Stored working memory {memory.id} (TTL={ttl}s, importance={memory.importance})")
    return memory.id


async def get(session_id: str, memory_id: str) -> WorkingMemory | None:
    """Get a single working memory by ID."""
    data = await _ms_get(session_id, memory_id)
    if data is None:
        return None
    return WorkingMemory(**data)


async def get_all(session_id: str) -> list[WorkingMemory]:
    """Get all active working memories for a session."""
    all_data = await _ms_get_all(session_id)
    memories = [WorkingMemory(**d) for d in all_data]
    # Sort by created_at descending (newest first)
    memories.sort(key=lambda m: m.created_at, reverse=True)
    return memories


async def query(session_id: str, query_text: str, limit: int = 10) -> list[WorkingMemory]:
    """Query working memories by keyword matching."""
    all_memories = await get_all(session_id)

    if not query_text.strip():
        return all_memories[:limit]

    query_lower = query_text.lower()
    query_words = set(query_lower.split())

    scored: list[tuple[float, WorkingMemory]] = []

    for mem in all_memories:
        score = 0.0
        content_lower = mem.content.lower()

        # Exact substring match (highest score)
        if query_lower in content_lower:
            score += 3.0

        # Word overlap scoring
        content_words = set(content_lower.split())
        overlap = query_words & content_words
        if overlap:
            score += len(overlap) / len(query_words) * 2.0

        # Topic tag match
        for tag in mem.topic_tags:
            if tag.lower() in query_lower or query_lower in tag.lower():
                score += 1.5

        # Importance boost
        score *= (0.5 + mem.importance)

        if score > 0:
            scored.append((score, mem))

    # Sort by score descending
    scored.sort(key=lambda x: x[0], reverse=True)

    results = [mem for _, mem in scored[:limit]]

    # Publish query event
    event = json.dumps({
        "type": "memory_queried",
        "tier": "working",
        "session_id": session_id,
        "query": query_text,
        "results_count": len(results),
        "timestamp": datetime.now(timezone.utc).isoformat(),
    })
    await publish_event(CHANNEL, event)

    return results


async def flush(session_id: str) -> int:
    """Delete all working memories for a session. Returns count of deleted."""
    count_deleted = await _ms_flush(session_id)

    logger.info(f"Flushed {count_deleted} working memories for session {session_id}")

    # Publish flush event
    event = json.dumps({
        "type": "working_memory_flushed",
        "session_id": session_id,
        "memories_flushed": count_deleted,
        "timestamp": datetime.now(timezone.utc).isoformat(),
    })
    await publish_event(CHANNEL, event)

    return count_deleted


async def get_ttl(session_id: str, memory_id: str) -> int:
    """Get remaining TTL for a working memory in seconds."""
    ttl = await _ms_get_ttl(session_id, memory_id)
    return max(ttl, 0)


async def count(session_id: str) -> int:
    """Count active working memories for a session."""
    return await _ms_count(session_id)
