"""
Reflection Engine для Степана (Deep mode only).

reflect_on_response(user_input, final_response, user_profile, farm_profile)
  → dict з полями: new_facts, style_shift, confidence, clarifying_question

Правила:
  - НЕ генерує нову відповідь, тільки аналізує
  - НЕ запускається в Light mode
  - НЕ запускається рекурсивно (_REFLECTING flag)
  - При будь-якій помилці → повертає safe_fallback()
  - confidence < 0.6 → викликаючий код може додати clarifying_question до відповіді

Anti-recursion:
  Три рівні захисту:
    1. Модульний boolean _REFLECTING (per-process, cleared у finally)
    2. Caller у run.py передає depth="deep" — reflection ніколи не викличе handle_message
    3. Reflection не імпортує run.py, не використовує Crew/Agent

Fail-safe: повертає safe_fallback() при будь-якому винятку.
"""

from __future__ import annotations

import logging
import re
from typing import Any

logger = logging.getLogger(__name__)

# ─── Anti-recursion guard ─────────────────────────────────────────────────────

_REFLECTING: bool = False


def _safe_fallback() -> dict[str, Any]:
    return {
        "new_facts": {},
        "style_shift": None,
        "confidence": 1.0,
        "clarifying_question": None,
    }


# ─── Fact extraction (rule-based) ────────────────────────────────────────────

_CROP_RE = re.compile(
    r'\b(пшениця|кукурудза|соняшник|ріпак|соя|ячмінь|жито|гречка|овес|цукровий\s+буряк)\b',
    re.IGNORECASE | re.UNICODE,
)
_REGION_RE = re.compile(
    r'\b(область|район|село|місто|регіон|зона)\s+([\w-]+)',
    re.IGNORECASE | re.UNICODE,
)
_ROLE_RE = re.compile(
    r'\b(я\s+)?(агроном|власник|господар|оператор|механік|агрономка|директор)\b',
    re.IGNORECASE | re.UNICODE,
)
_NAME_RE = re.compile(
    r'\b(мене\s+звуть|я\s+[-—]?\s*|мене\s+кличуть)\s+([А-ЯІЇЄA-Z][а-яіїєa-z]{2,})',
    re.UNICODE,
)

_STYLE_SIGNAL: dict[str, list[str]] = {
    "concise":    ["коротко", "стисло", "без деталей"],
    "checklist":  ["списком", "маркерами", "пунктами"],
    "analytical": ["аналіз", "причини", "наслідки"],
    "detailed":   ["детально", "докладно", "розгорнуто"],
}

_UNCERTAINTY_PHRASES = [
    "не впевнений", "не зрозуміло", "не знаю", "можливо", "мабуть",
    "не ясно", "незрозуміло", "не зрозумів", "не визначив", "відсутні дані",
    "потрібно уточнити", "уточніть",
]


def _extract_new_facts(user_input: str, response: str, user_profile: dict | None, farm_profile: dict | None) -> dict:
    facts: dict[str, Any] = {}
    up = user_profile or {}
    fp = farm_profile or {}

    # Name
    m = _NAME_RE.search(user_input)
    if m and not up.get("name"):
        facts["name"] = m.group(2)

    # Role
    m = _ROLE_RE.search(user_input)
    if m and up.get("role") == "unknown":
        role_map = {
            "агроном": "agronomist", "агрономка": "agronomist",
            "власник": "owner", "господар": "owner", "директор": "owner",
            "оператор": "operator", "механік": "mechanic",
        }
        raw = m.group(2).lower()
        for k, v in role_map.items():
            if k in raw:
                facts["role"] = v
                break

    # Crops (new ones not yet in farm profile)
    existing_crops = set(fp.get("crops", []))
    found_crops = {m.group(0).lower() for m in _CROP_RE.finditer(user_input)}
    new_crops = found_crops - existing_crops
    if new_crops:
        facts["new_crops"] = list(new_crops)

    # Style shift from user phrasing
    tl = user_input.lower()
    for style, signals in _STYLE_SIGNAL.items():
        if any(s in tl for s in signals) and up.get("style") != style:
            facts["style_shift"] = style
            break

    return facts


def _compute_confidence(user_input: str, response: str) -> float:
    """
    Оцінити впевненість відповіді (0..1).
    Низька впевненість якщо відповідь містить ознаки невизначеності.
    """
    resp_lower = response.lower()
    uncertainty_count = sum(1 for ph in _UNCERTAINTY_PHRASES if ph in resp_lower)
    if uncertainty_count >= 3:
        return 0.4
    if uncertainty_count >= 1:
        return 0.55
    # Response too short for the complexity of the question
    if len(response) < 80 and len(user_input) > 150:
        return 0.5
    return 0.85


def _build_clarifying_question(user_input: str, response: str, facts: dict) -> str | None:
    """
    Сформувати одне уточнювальне питання якщо потрібно.
    Повертає None якщо питання не потрібне.
    """
    if facts.get("new_crops"):
        crops_str = ", ".join(facts["new_crops"])
        return f"Уточніть: ці культури ({crops_str}) відносяться до поточного сезону?"
    resp_lower = response.lower()
    if "потрібно уточнити" in resp_lower or "уточніть" in resp_lower:
        # Response itself already asks; no need to double
        return None
    if "не зрозуміло" in resp_lower or "не визначив" in resp_lower:
        return "Чи можете уточнити — що саме вас цікавить найбільше?"
    return None


# ─── Public API ───────────────────────────────────────────────────────────────

def reflect_on_response(
    user_input: str,
    final_response: str,
    user_profile: dict | None,
    farm_profile: dict | None,
) -> dict[str, Any]:
    """
    Аналізує відповідь після Deep mode.

    Повертає:
      {
        "new_facts":           dict  — нові факти для запису в профіль
        "style_shift":         str | None — новий стиль якщо виявлено
        "confidence":          float 0..1 — впевненість відповіді
        "clarifying_question": str | None — питання для користувача якщо confidence < 0.6
      }

    НЕ запускається рекурсивно.
    Fail-safe: будь-який виняток → _safe_fallback().
    """
    global _REFLECTING

    if _REFLECTING:
        from crews.agromatrix_crew.telemetry import tlog as _tlog
        _tlog(logger, "reflection_skip", reason="recursion_guard")
        logger.warning("reflection_engine: recursion guard active — skipping")
        return _safe_fallback()

    _REFLECTING = True
    try:
        if not user_input or not final_response:
            return _safe_fallback()

        facts = _extract_new_facts(user_input, final_response, user_profile, farm_profile)
        confidence = _compute_confidence(user_input, final_response)

        style_shift = facts.pop("style_shift", None)
        clarifying_question: str | None = None

        from crews.agromatrix_crew.telemetry import tlog as _tlog
        if confidence < 0.6:
            clarifying_question = _build_clarifying_question(user_input, final_response, facts)
            _tlog(logger, "reflection_done", confidence=round(confidence, 2),
                  clarifying=bool(clarifying_question), new_facts=list(facts.keys()))
            logger.info(
                "reflection_engine: low confidence=%.2f clarifying=%s",
                confidence,
                bool(clarifying_question),
            )
        else:
            _tlog(logger, "reflection_done", confidence=round(confidence, 2),
                  clarifying=False, new_facts=list(facts.keys()))
            logger.debug("reflection_engine: confidence=%.2f no clarification needed", confidence)

        if facts:
            logger.info("reflection_engine: new_facts=%s", list(facts.keys()))

        return {
            "new_facts": facts,
            "style_shift": style_shift,
            "confidence": confidence,
            "clarifying_question": clarifying_question,
        }

    except Exception as exc:
        from crews.agromatrix_crew.telemetry import tlog as _tlog
        _tlog(logger, "reflection_skip", reason="error", error=str(exc))
        logger.warning("reflection_engine: error (fallback): %s", exc)
        return _safe_fallback()

    finally:
        _REFLECTING = False
