"""IMA Pipeline — 5-Stage Intelligent Memory Arbitration.

Orchestrates the full IMA pipeline:
  Stage 1: Classification (local heuristic) — filter trivial (~70% eliminated)
  Stage 2: Duplicate Check (local embedding) — merge/skip near-duplicates
  Stage 3: AI Depth Decision (multi-provider) — importance/detail/retention
  Stage 4: Smart Compression — full/summary/key_only
  Stage 5: Store + Link — delegate to existing SOAGILA storage pipeline

Cost breakdown per 100 messages:
  - Stage 1 eliminates ~70 → 30 remain
  - Stage 2 eliminates ~5 → 25 remain
  - Stage 3 AI call on ~25 (if provider configured, else local) → ~$0.005
  - Total: ~$1.50/month for active user
"""

import logging
import time
from dataclasses import dataclass, field

from soagila.core.ima.classifier import classify, ClassificationResult
from soagila.core.ima.dedup import check_duplicate, merge_memories, DedupResult
from soagila.core.ima.ai_bridge import get_depth_decision, DepthDecision
from soagila.core.ima.compressor import compress, CompressedContent
from soagila.core.ima import self_learning

logger = logging.getLogger("soagila.ima.pipeline")


@dataclass
class IMAPipelineResult:
    """Final result of the IMA pipeline."""
    action: str                     # "store" | "merge" | "skip"
    content: str                    # Final content to store (may be compressed)
    original_content: str           # Original unmodified content
    importance: float
    detail_level: str               # full / summary / key_only
    category: str
    retention_days: int
    merge_target_id: str | None     # If action=merge, the target memory ID
    pipeline_stages: list[dict] = field(default_factory=list)
    duration_ms: float = 0.0
    ai_provider: str = "local"
    ai_cost: float = 0.0

    def to_dict(self) -> dict:
        return {
            "action": self.action,
            "importance": round(self.importance, 3),
            "detail_level": self.detail_level,
            "category": self.category,
            "retention_days": self.retention_days,
            "merge_target_id": self.merge_target_id,
            "content_length": len(self.content),
            "original_length": len(self.original_content),
            "compression_ratio": round(len(self.content) / len(self.original_content), 3) if self.original_content else 1.0,
            "pipeline_stages": self.pipeline_stages,
            "duration_ms": round(self.duration_ms, 2),
            "ai_provider": self.ai_provider,
            "ai_cost": round(self.ai_cost, 6),
        }


async def run(
    content: str,
    topic_tags: list[str] | None = None,
    importance_hint: float = 0.5,
    user_id: str = "local",
    skip_ai: bool = False,
) -> IMAPipelineResult:
    """Run the full IMA 5-stage pipeline.

    Args:
        content: Raw content to process.
        topic_tags: Optional topic tags from the caller.
        importance_hint: Caller's importance hint (0-1).
        user_id: User ID for dedup search scope.
        skip_ai: If True, skip Stage 3 AI call (use local heuristics).

    Returns:
        IMAPipelineResult with action and final content.
    """
    start_time = time.time()
    stages: list[dict] = []

    # ════════════════════════════════════════════════════════════════════════
    # STAGE 1: Classification (Local Heuristic)
    # ════════════════════════════════════════════════════════════════════════
    classification: ClassificationResult = classify(content)
    stages.append({
        "stage": 1,
        "name": "classification",
        **classification.to_dict(),
    })

    if classification.is_trivial and classification.confidence >= 0.8 and importance_hint < 0.8:
        # High-confidence trivial AND caller didn't insist on importance — skip
        # If importance_hint >= 0.8, caller explicitly marked this as important → bypass filter
        self_learning.record_trivial_filter()
        duration = (time.time() - start_time) * 1000

        logger.info(f"IMA pipeline: SKIP (trivial, confidence={classification.confidence})")
        return IMAPipelineResult(
            action="skip",
            content=content,
            original_content=content,
            importance=0.0,
            detail_level="none",
            category="trivial",
            retention_days=0,
            merge_target_id=None,
            pipeline_stages=stages,
            duration_ms=duration,
        )

    # Use higher of caller hint and classifier hint
    working_importance = max(importance_hint, classification.importance_hint)
    working_category = classification.category

    # ════════════════════════════════════════════════════════════════════════
    # STAGE 2: Duplicate Check (Local Embedding)
    # ════════════════════════════════════════════════════════════════════════
    dedup: DedupResult = await check_duplicate(content, user_id)
    stages.append({
        "stage": 2,
        "name": "dedup",
        **dedup.to_dict(),
    })

    if dedup.action == "skip":
        self_learning.record_duplicate_skip()
        duration = (time.time() - start_time) * 1000

        logger.info(f"IMA pipeline: SKIP (duplicate of {dedup.duplicate_id})")
        return IMAPipelineResult(
            action="skip",
            content=content,
            original_content=content,
            importance=0.0,
            detail_level="none",
            category=working_category,
            retention_days=0,
            merge_target_id=dedup.duplicate_id,
            pipeline_stages=stages,
            duration_ms=duration,
        )

    if dedup.action == "merge":
        # Merge into existing memory
        merged_id = await merge_memories(dedup.duplicate_id, content)  # type: ignore
        self_learning.record_duplicate_merge()
        duration = (time.time() - start_time) * 1000

        logger.info(f"IMA pipeline: MERGE into {merged_id}")
        return IMAPipelineResult(
            action="merge",
            content=content,
            original_content=content,
            importance=working_importance,
            detail_level="full",
            category=working_category,
            retention_days=90,
            merge_target_id=merged_id,
            pipeline_stages=stages,
            duration_ms=duration,
        )

    # ════════════════════════════════════════════════════════════════════════
    # STAGE 3: AI Depth Decision
    # ════════════════════════════════════════════════════════════════════════
    depth: DepthDecision
    if skip_ai:
        from soagila.core.ima.ai_bridge import _local_depth_decision
        depth = _local_depth_decision(content, working_category, working_importance)
    else:
        depth = await get_depth_decision(content, working_category, working_importance)

    stages.append({
        "stage": 3,
        "name": "depth_decision",
        **depth.to_dict(),
    })

    # AI may override category and importance
    final_importance = max(working_importance, depth.importance)
    final_category = depth.category if depth.provider != "local" else working_category

    # ════════════════════════════════════════════════════════════════════════
    # STAGE 4: Smart Compression
    # ════════════════════════════════════════════════════════════════════════
    compressed: CompressedContent = compress(
        content,
        depth.detail_level,
        summary=depth.summary,
        key_points=depth.key_points,
    )
    stages.append({
        "stage": 4,
        "name": "compression",
        **compressed.to_dict(),
    })

    # ════════════════════════════════════════════════════════════════════════
    # STAGE 5: Result (actual storage delegated to caller)
    # ════════════════════════════════════════════════════════════════════════
    duration = (time.time() - start_time) * 1000

    self_learning.record_store(
        detail_level=depth.detail_level,
        ai_called=depth.provider != "local",
        cost=depth.cost_estimate,
    )

    stages.append({
        "stage": 5,
        "name": "ready_to_store",
        "final_importance": round(final_importance, 3),
        "final_category": final_category,
        "retention_days": depth.retention_days,
    })

    logger.info(
        f"IMA pipeline: STORE ({depth.detail_level}) — "
        f"importance={final_importance:.2f}, category={final_category}, "
        f"compression={compressed.compression_ratio:.2f}, "
        f"provider={depth.provider}, duration={duration:.1f}ms"
    )

    return IMAPipelineResult(
        action="store",
        content=compressed.content,
        original_content=content,
        importance=final_importance,
        detail_level=depth.detail_level,
        category=final_category,
        retention_days=depth.retention_days,
        merge_target_id=None,
        pipeline_stages=stages,
        duration_ms=duration,
        ai_provider=depth.provider,
        ai_cost=depth.cost_estimate,
    )
