"""Advanced LLM consolidation with chain-of-thought reasoning."""

from __future__ import annotations

import json
import logging
from typing import Any

from neurovault.cognitive.llm_client import OllamaClient

logger = logging.getLogger(__name__)

COT_SYSTEM = """You are NEUROVAULT's deep reasoning engine. You analyze memory
clusters using a structured chain-of-thought process to discover hidden
connections that simpler analysis would miss.

You MUST follow this 4-step reasoning process:
1. IDENTIFY: What are the key themes in these memories?
2. CONNECT: What non-obvious connections exist between themes?
3. INFER: What does the pattern suggest about the user's trajectory?
4. SYNTHESIZE: Generate a single actionable insight.

Be specific, cite facts from the memories, and never fabricate."""


class AdvancedLLMConsolidation:
    """Multi-step LLM reasoning for insight generation and cross-domain links."""

    def __init__(self, client: OllamaClient | None = None):
        self._client = client or OllamaClient()

    def chain_of_thought_insight(
        self,
        memories: list[dict[str, Any]],
        entities: list[str],
        relationships: list[dict[str, Any]],
    ) -> dict[str, Any]:
        if not self._client.is_available():
            return {
                "reasoning_chain": [],
                "insight": self._template_fallback(memories, entities),
                "llm_used": False,
            }

        mem_block = "\n".join(f"  [{i + 1}] {m.get('content', '')[:150]}" for i, m in enumerate(memories[:10]))
        ent_block = ", ".join(entities[:10])
        rel_block = "\n".join(
            f"  - {r.get('source', '?')} -> {r.get('type', '?')} -> {r.get('target', '?')}" for r in relationships[:10]
        )

        prompt = f"""Analyze this cluster of {len(memories)} related memories:

Key entities: {ent_block}
Key relationships:
{rel_block}

Memory samples:
{mem_block}

Follow the 4-step reasoning process (IDENTIFY -> CONNECT -> INFER -> SYNTHESIZE).
Format your response as JSON:
{{
  "identify": "key themes found...",
  "connect": "non-obvious connections...",
  "infer": "what this suggests...",
  "synthesize": "final actionable insight..."
}}"""

        raw = self._client.generate(
            prompt=prompt,
            system=COT_SYSTEM,
            temperature=0.3,
            max_tokens=1024,
        )
        return self._parse_cot_response(raw, memories, entities)

    def cross_domain_association(self, cluster_a: dict[str, Any], cluster_b: dict[str, Any]) -> dict[str, Any] | None:
        if not self._client.is_available():
            return None

        prompt = f"""Find a surprising connection between these two knowledge domains:

Domain A - \"{cluster_a.get('label', 'Unknown')}\":
{chr(10).join(f'  - {m[:100]}' for m in cluster_a.get('memory_samples', [])[:5])}

Domain B - \"{cluster_b.get('label', 'Unknown')}\":
{chr(10).join(f'  - {m[:100]}' for m in cluster_b.get('memory_samples', [])[:5])}

Is there a meaningful connection? If yes, explain in 2-3 sentences.
If no genuine connection exists, respond with \"NO_CONNECTION\"."""

        result = self._client.generate(prompt=prompt, temperature=0.4, max_tokens=256)
        if not result or "NO_CONNECTION" in result:
            return None

        return {
            "cluster_a": cluster_a.get("id", ""),
            "cluster_b": cluster_b.get("id", ""),
            "connection": result,
            "type": "cross-domain",
        }

    def quality_score_insight(self, insight_text: str) -> float:
        if not self._client.is_available():
            return 0.5

        prompt = f"""Rate this insight on a scale of 1-10:

\"{insight_text}\"

Criteria:
- Specificity (cites concrete facts): 1-3 points
- Novelty (non-obvious connection): 1-3 points
- Actionability (suggests what to do): 1-4 points

Reply with just the numeric score (1-10):"""

        raw = self._client.generate(prompt=prompt, temperature=0.1, max_tokens=5)
        try:
            score = int(str(raw).strip().split()[0])
            return min(max(score / 10.0, 0.1), 1.0)
        except Exception as exc:
            logger.debug("Insight quality score parsing failed: %s", exc)
            return 0.5

    def _parse_cot_response(self, raw: str, memories: list[dict[str, Any]], entities: list[str]) -> dict[str, Any]:
        try:
            start = raw.find("{")
            end = raw.rfind("}") + 1
            if start >= 0 and end > start:
                cot = json.loads(raw[start:end])
                return {
                    "reasoning_chain": [
                        cot.get("identify", ""),
                        cot.get("connect", ""),
                        cot.get("infer", ""),
                    ],
                    "insight": cot.get("synthesize", raw),
                    "llm_used": True,
                }
        except Exception as exc:
            logger.debug("CoT response parsing failed; using fallback insight: %s", exc)

        return {
            "reasoning_chain": [],
            "insight": raw if len(raw) > 20 else self._template_fallback(memories, entities),
            "llm_used": bool(raw),
        }

    @staticmethod
    def _template_fallback(memories: list[dict[str, Any]], entities: list[str]) -> str:
        ent = ", ".join(entities[:3]) if entities else "various topics"
        return f"Knowledge pattern ({len(memories)} connected memories): {ent}"
