"""Memory Arbitration Engine (MAE) — conflict detection and resolution.

Minimal changes: updated imports to use soagila.* prefix and event_bus.
All logic preserved exactly as-is.
"""

import json
import logging
from datetime import datetime, timezone

from soagila.core.mae.models import Conflict, ConflictType, ArbitrationResult
from soagila.core.mae.strategies import (
    get_tier_weights,
    resolve_contradiction,
    resolve_tension,
    resolve_temporal_sequence,
)
from soagila.core.tcmg.memory_models import WorkingMemory, EpisodicMemory, SemanticMemory
from soagila.core.tcmg.embedding_service import cosine_similarity
from soagila.db.event_bus import publish_event

logger = logging.getLogger("soagila.mae.arbitrator")

CHANNEL = "soagila:metrics"

# Thresholds for conflict detection
CONTRADICTION_SIMILARITY_THRESHOLD = 0.5   # High topic similarity but...
CONTRADICTION_SENTIMENT_KEYWORDS = {
    "positive": {"happy", "satisfied", "great", "good", "memnun", "harika", "iyi", "teşekkür", "pleased", "excellent"},
    "negative": {"unhappy", "complaint", "expensive", "high", "bad", "şikayet", "pahalı", "yüksek", "sorun", "problem", "issue"},
}


def _extract_sentiment(text: str) -> str:
    """Simple keyword-based sentiment detection."""
    text_lower = text.lower()
    pos_count = sum(1 for w in CONTRADICTION_SENTIMENT_KEYWORDS["positive"] if w in text_lower)
    neg_count = sum(1 for w in CONTRADICTION_SENTIMENT_KEYWORDS["negative"] if w in text_lower)

    if pos_count > neg_count:
        return "positive"
    elif neg_count > pos_count:
        return "negative"
    return "neutral"


def detect_conflicts(
    working: list[WorkingMemory],
    episodic: list[EpisodicMemory],
    semantic: list[SemanticMemory],
) -> list[Conflict]:
    """
    Detect conflicts between memory tiers.
    Classifies as: Contradiction, Tension, or Temporal Sequence.
    """
    conflicts = []

    # Collect all memories with embeddings for comparison
    all_memories = []
    for m in working:
        all_memories.append(("working", m.id, m.content, getattr(m, 'embedding', None), m.created_at))
    for m in episodic:
        all_memories.append(("episodic", m.id, m.content, getattr(m, 'embedding', None), m.created_at))
    for m in semantic:
        all_memories.append(("semantic", m.id, m.content, None, m.created_at))

    # Compare across different tiers
    for i in range(len(all_memories)):
        for j in range(i + 1, len(all_memories)):
            tier_a, id_a, content_a, emb_a, time_a = all_memories[i]
            tier_b, id_b, content_b, emb_b, time_b = all_memories[j]

            # Only compare across different tiers
            if tier_a == tier_b:
                continue

            # Check topic similarity
            sim = 0.0
            if emb_a and emb_b:
                sim = cosine_similarity(emb_a, emb_b)
            else:
                # Fallback: keyword overlap
                words_a = set(content_a.lower().split())
                words_b = set(content_b.lower().split())
                if words_a and words_b:
                    overlap = words_a & words_b
                    sim = len(overlap) / max(len(words_a | words_b), 1)

            # Only consider as potential conflict if topics are related
            if sim < 0.3:
                continue

            # Detect conflict type
            sentiment_a = _extract_sentiment(content_a)
            sentiment_b = _extract_sentiment(content_b)

            conflict_type = None

            # CONTRADICTION: Same topic, opposing sentiments
            if sentiment_a != "neutral" and sentiment_b != "neutral" and sentiment_a != sentiment_b:
                conflict_type = ConflictType.CONTRADICTION

            # TEMPORAL SEQUENCE: Same topic, different time periods, noticeable time gap
            elif time_a and time_b and abs((time_a - time_b).total_seconds()) > 3600:
                conflict_type = ConflictType.TEMPORAL_SEQUENCE

            # TENSION: Similar topic but different emphasis/strategy implied
            elif sim >= 0.4 and sentiment_a != sentiment_b:
                conflict_type = ConflictType.TENSION

            if conflict_type:
                conflicts.append(Conflict(
                    conflict_type=conflict_type,
                    description=f"{conflict_type.value} between {tier_a} and {tier_b}",
                    tiers_involved=[tier_a, tier_b],
                    memory_a_id=id_a,
                    memory_a_tier=tier_a,
                    memory_a_content=content_a,
                    memory_b_id=id_b,
                    memory_b_tier=tier_b,
                    memory_b_content=content_b,
                    similarity_score=sim,
                ))

    return conflicts


async def resolve(
    conflicts: list[Conflict],
    task_context: str,
    working: list[WorkingMemory],
    episodic: list[EpisodicMemory],
    semantic: list[SemanticMemory],
) -> ArbitrationResult:
    """
    Resolve detected conflicts using appropriate strategies.
    Returns unified ArbitrationResult with explanation.
    """
    if not conflicts:
        return ArbitrationResult(
            conflicts_detected=0,
            resolution_strategy="none",
            explanation="No conflicts detected between memory tiers. All information is complementary.",
        )

    weights = get_tier_weights(task_context)
    resolutions = []

    # Gather tier content summaries
    working_summary = "; ".join([m.content[:100] for m in working[:3]]) if working else ""
    episodic_summary = "; ".join([m.content[:100] for m in episodic[:3]]) if episodic else ""
    semantic_summary = "; ".join([m.content[:100] for m in semantic[:3]]) if semantic else ""

    primary_strategy = "none"

    for conflict in conflicts:
        if conflict.conflict_type == ConflictType.CONTRADICTION:
            resolution = resolve_contradiction(
                conflict, task_context,
                working_summary, episodic_summary, semantic_summary,
            )
            primary_strategy = "task_priority"
        elif conflict.conflict_type == ConflictType.TENSION:
            resolution = resolve_tension(conflict, task_context)
            if primary_strategy == "none":
                primary_strategy = "weighted_synthesis"
        elif conflict.conflict_type == ConflictType.TEMPORAL_SEQUENCE:
            resolution = resolve_temporal_sequence(conflict)
            if primary_strategy == "none":
                primary_strategy = "temporal_analysis"
        else:
            resolution = {"strategy": "pass_through", "explanation": "Unknown conflict type."}

        resolutions.append(resolution)

    # Build unified explanation
    explanations = [r["explanation"] for r in resolutions]
    unified_explanation = " | ".join(explanations)

    # Determine winner tier (from contradictions)
    winner_tier = None
    for r in resolutions:
        if "winner_tier" in r:
            winner_tier = r["winner_tier"]
            break

    # Build unified context
    context_parts = []
    if working_summary:
        context_parts.append(f"[Current Context] {working_summary}")
    if episodic_summary:
        context_parts.append(f"[Recent History] {episodic_summary}")
    if semantic_summary:
        context_parts.append(f"[Known Patterns] {semantic_summary}")
    if unified_explanation:
        context_parts.append(f"[Arbitration Note] {unified_explanation}")
    unified_context = "\n".join(context_parts)

    result = ArbitrationResult(
        conflicts_detected=len(conflicts),
        conflicts=conflicts,
        resolution_strategy=primary_strategy,
        winner_tier=winner_tier,
        unified_context=unified_context,
        explanation=unified_explanation,
        tier_weights=weights,
    )

    # Publish arbitration event
    event = json.dumps({
        "type": "arbitration_occurred",
        "conflict_count": len(conflicts),
        "conflict_types": [c.conflict_type.value for c in conflicts],
        "resolution_strategy": primary_strategy,
        "winner_tier": winner_tier,
        "tiers_involved": list(set(t for c in conflicts for t in c.tiers_involved)),
        "timestamp": datetime.now(timezone.utc).isoformat(),
    })
    await publish_event(CHANNEL, event)

    logger.info(
        f"Arbitration: {len(conflicts)} conflicts detected, "
        f"strategy={primary_strategy}, winner={winner_tier}"
    )

    return result


async def arbitrate(
    working: list[WorkingMemory],
    episodic: list[EpisodicMemory],
    semantic: list[SemanticMemory],
    task_context: str = "general",
) -> ArbitrationResult:
    """Full arbitration pipeline: detect + resolve."""
    conflicts = detect_conflicts(working, episodic, semantic)
    return await resolve(conflicts, task_context, working, episodic, semantic)
