"""IMA Stage 3 — AI Bridge (Multi-Provider Depth Decision).

Asks user's chosen AI provider for:
  - importance (0-1)
  - detail_level: full / summary / key_only
  - category refinement
  - suggested retention days

Supports: Claude, OpenAI, Gemini, Grok, DeepSeek.
Falls back to local heuristics if no API key configured.

Cost control: Only ~15% of content reaches this stage (after classifier + dedup).
"""

import os
import json
import logging
from dataclasses import dataclass

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

SUPPORTED_PROVIDERS = ["claude", "openai", "gemini", "grok", "deepseek", "local"]

DEPTH_DECISION_PROMPT = """You are a memory importance evaluator for a software development AI assistant.

Analyze the following content and decide how it should be stored in long-term memory.

Content to evaluate:
---
{content}
---

Context category (from heuristic): {category}
Heuristic importance hint: {importance_hint}

Respond ONLY with a JSON object (no markdown, no explanation):
{{
  "importance": <float 0.0-1.0>,
  "detail_level": "<full|summary|key_only>",
  "category": "<architecture|bug_fix|configuration|security|preference|performance|documentation|general>",
  "retention_days": <integer 7-365>,
  "summary": "<one-line summary if detail_level is summary or key_only, else null>",
  "key_points": [<list of key points if detail_level is key_only, else null>],
  "reasoning": "<brief explanation of your decision>"
}}

Guidelines:
- importance 0.9-1.0: Architectural decisions, critical bug fixes, security issues
- importance 0.6-0.8: Configuration changes, preferences, moderate decisions
- importance 0.3-0.5: General context, minor details
- importance 0.0-0.2: Should not have reached this stage

- detail_level "full": Store entire content (architectural decisions, complex bug fixes)
- detail_level "summary": Store a condensed version (long discussions, verbose explanations)
- detail_level "key_only": Store only key facts (configuration values, simple preferences)
"""


@dataclass
class DepthDecision:
    """Result of Stage 3 AI depth decision."""
    importance: float
    detail_level: str       # full / summary / key_only
    category: str
    retention_days: int
    summary: str | None
    key_points: list[str] | None
    reasoning: str
    provider: str           # Which AI made this decision
    cost_estimate: float    # Estimated cost in USD

    def to_dict(self) -> dict:
        return {
            "importance": self.importance,
            "detail_level": self.detail_level,
            "category": self.category,
            "retention_days": self.retention_days,
            "summary": self.summary,
            "key_points": self.key_points,
            "reasoning": self.reasoning,
            "provider": self.provider,
            "cost_estimate": round(self.cost_estimate, 6),
        }


def get_configured_provider() -> str:
    """Detect which AI provider is configured via environment variables."""
    if os.environ.get("ANTHROPIC_API_KEY"):
        return "claude"
    if os.environ.get("OPENAI_API_KEY"):
        return "openai"
    if os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY"):
        return "gemini"
    if os.environ.get("GROK_API_KEY") or os.environ.get("XAI_API_KEY"):
        return "grok"
    if os.environ.get("DEEPSEEK_API_KEY"):
        return "deepseek"
    return "local"


async def get_depth_decision(
    content: str,
    category: str,
    importance_hint: float,
    provider: str | None = None,
) -> DepthDecision:
    """Ask AI for depth decision. Falls back to local heuristics if no provider."""
    if provider is None:
        provider = os.environ.get("SOAGILA_AI_PROVIDER", get_configured_provider())

    if provider == "local":
        return _local_depth_decision(content, category, importance_hint)

    try:
        if provider == "claude":
            return await _claude_decision(content, category, importance_hint)
        elif provider == "openai":
            return await _openai_decision(content, category, importance_hint)
        elif provider == "gemini":
            return await _gemini_decision(content, category, importance_hint)
        elif provider == "grok":
            return await _grok_decision(content, category, importance_hint)
        elif provider == "deepseek":
            return await _deepseek_decision(content, category, importance_hint)
        else:
            logger.warning(f"Unknown provider '{provider}', falling back to local")
            return _local_depth_decision(content, category, importance_hint)
    except Exception as e:
        logger.warning(f"AI Bridge error ({provider}): {e}. Falling back to local.")
        return _local_depth_decision(content, category, importance_hint)


# ── Local Heuristic Fallback ──────────────────────────────────────────────────

def _local_depth_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Local heuristic-based depth decision. Zero API cost."""
    words = content.split()
    word_count = len(words)

    # Detail level based on content length and importance
    if importance_hint >= 0.8 or category in ("architecture", "security"):
        detail_level = "full"
    elif word_count > 300:
        detail_level = "summary"
    elif importance_hint <= 0.4 or category in ("configuration", "preference"):
        detail_level = "key_only"
    else:
        detail_level = "full"

    # Retention based on category
    retention_map = {
        "architecture": 365,
        "security": 365,
        "bug_fix": 180,
        "performance": 180,
        "configuration": 90,
        "preference": 365,
        "documentation": 90,
        "general": 30,
    }
    retention_days = retention_map.get(category, 90)

    # Generate summary for non-full detail levels
    summary = None
    key_points = None

    if detail_level == "summary":
        # Simple extractive summary: first 2 sentences
        sentences = content.replace("\n", " ").split(". ")
        summary = ". ".join(sentences[:2]).strip()
        if not summary.endswith("."):
            summary += "."
    elif detail_level == "key_only":
        # Extract lines that look like key-value pairs or short facts
        lines = content.strip().split("\n")
        key_points = [
            line.strip() for line in lines
            if line.strip() and len(line.strip()) < 200
        ][:10]

    return DepthDecision(
        importance=importance_hint,
        detail_level=detail_level,
        category=category,
        retention_days=retention_days,
        summary=summary,
        key_points=key_points,
        reasoning="local heuristic (no AI provider configured)",
        provider="local",
        cost_estimate=0.0,
    )


# ── Claude (Anthropic) ───────────────────────────────────────────────────────

async def _claude_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Use Claude Haiku for depth decision (~$0.0003 per call)."""
    import httpx

    api_key = os.environ.get("ANTHROPIC_API_KEY", "")
    prompt = DEPTH_DECISION_PROMPT.format(
        content=content[:2000], category=category, importance_hint=importance_hint
    )

    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.post(
            "https://api.anthropic.com/v1/messages",
            headers={
                "x-api-key": api_key,
                "anthropic-version": "2023-06-01",
                "content-type": "application/json",
            },
            json={
                "model": "claude-haiku-4-5-20251001",
                "max_tokens": 300,
                "messages": [{"role": "user", "content": prompt}],
            },
        )
        resp.raise_for_status()
        data = resp.json()
        text = data["content"][0]["text"]
        result = json.loads(text)

    return _parse_ai_response(result, "claude", 0.0003)


# ── OpenAI ────────────────────────────────────────────────────────────────────

async def _openai_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Use GPT-4o-mini for depth decision (~$0.0002 per call)."""
    import httpx

    api_key = os.environ.get("OPENAI_API_KEY", "")
    prompt = DEPTH_DECISION_PROMPT.format(
        content=content[:2000], category=category, importance_hint=importance_hint
    )

    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.post(
            "https://api.openai.com/v1/chat/completions",
            headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
            json={
                "model": "gpt-4o-mini",
                "max_tokens": 300,
                "messages": [{"role": "user", "content": prompt}],
                "response_format": {"type": "json_object"},
            },
        )
        resp.raise_for_status()
        data = resp.json()
        text = data["choices"][0]["message"]["content"]
        result = json.loads(text)

    return _parse_ai_response(result, "openai", 0.0002)


# ── Gemini ────────────────────────────────────────────────────────────────────

async def _gemini_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Use Gemini Flash for depth decision (~$0.0001 per call)."""
    import httpx

    api_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY", "")
    prompt = DEPTH_DECISION_PROMPT.format(
        content=content[:2000], category=category, importance_hint=importance_hint
    )

    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.post(
            f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}",
            headers={"Content-Type": "application/json"},
            json={
                "contents": [{"parts": [{"text": prompt}]}],
                "generationConfig": {"maxOutputTokens": 300, "responseMimeType": "application/json"},
            },
        )
        resp.raise_for_status()
        data = resp.json()
        text = data["candidates"][0]["content"]["parts"][0]["text"]
        result = json.loads(text)

    return _parse_ai_response(result, "gemini", 0.0001)


# ── Grok (xAI) ───────────────────────────────────────────────────────────────

async def _grok_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Use Grok for depth decision (~$0.0002 per call)."""
    import httpx

    api_key = os.environ.get("GROK_API_KEY") or os.environ.get("XAI_API_KEY", "")
    prompt = DEPTH_DECISION_PROMPT.format(
        content=content[:2000], category=category, importance_hint=importance_hint
    )

    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.post(
            "https://api.x.ai/v1/chat/completions",
            headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
            json={
                "model": "grok-3-mini-fast",
                "max_tokens": 300,
                "messages": [{"role": "user", "content": prompt}],
            },
        )
        resp.raise_for_status()
        data = resp.json()
        text = data["choices"][0]["message"]["content"]
        result = json.loads(text)

    return _parse_ai_response(result, "grok", 0.0002)


# ── DeepSeek ──────────────────────────────────────────────────────────────────

async def _deepseek_decision(content: str, category: str, importance_hint: float) -> DepthDecision:
    """Use DeepSeek for depth decision (~$0.0001 per call)."""
    import httpx

    api_key = os.environ.get("DEEPSEEK_API_KEY", "")
    prompt = DEPTH_DECISION_PROMPT.format(
        content=content[:2000], category=category, importance_hint=importance_hint
    )

    async with httpx.AsyncClient(timeout=15.0) as client:
        resp = await client.post(
            "https://api.deepseek.com/chat/completions",
            headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
            json={
                "model": "deepseek-chat",
                "max_tokens": 300,
                "messages": [{"role": "user", "content": prompt}],
                "response_format": {"type": "json_object"},
            },
        )
        resp.raise_for_status()
        data = resp.json()
        text = data["choices"][0]["message"]["content"]
        result = json.loads(text)

    return _parse_ai_response(result, "deepseek", 0.0001)


# ── Response Parser ───────────────────────────────────────────────────────────

def _parse_ai_response(result: dict, provider: str, cost: float) -> DepthDecision:
    """Parse AI response into DepthDecision."""
    return DepthDecision(
        importance=float(result.get("importance", 0.5)),
        detail_level=result.get("detail_level", "full"),
        category=result.get("category", "general"),
        retention_days=int(result.get("retention_days", 90)),
        summary=result.get("summary"),
        key_points=result.get("key_points"),
        reasoning=result.get("reasoning", f"{provider} decision"),
        provider=provider,
        cost_estimate=cost,
    )
