"""
doc_focus.py — Doc Focus Gate helpers (v3.5 / v3.6 / v3.7).

Без залежностей від crewai/agromatrix_tools — тільки re і stdlib.
Імпортується з run.py і operator_commands.py.

Публічні функції:
  _is_doc_question(text)            → bool
  _detect_domain(text, logger)      → str
  detect_context_signals(text)      → dict
  build_mode_clarifier(text)        → str
  handle_doc_focus(sub, chat_id)    → dict
"""
from __future__ import annotations

import re
import time

# ── Тригери: повідомлення явно про документ ──────────────────────────────────
_DOC_QUESTION_RE = re.compile(
    r"звіт|документ|таблиц|xlsx|sheet|рядок|колонк|в\s+звіті|у\s+файлі|у\s+документі"
    r"|по\s+звіту|з\s+(?:цього\s+)?файлу|в\s+цьому\s+документі|по\s+документу"
    r"|з\s+документа|відкрий\s+звіт",
    re.IGNORECASE | re.UNICODE,
)
# Фінансові тригери ТІЛЬКИ якщо є прив'язка до "документу/файлу"
_DOC_FINANCIAL_RE = re.compile(
    r"(?:прибуток|витрати?|собівартість|дохід|надходж|виручк|добрив|насінн|площ|гектар|грн|грн/га)"
    r".*(?:звіт|документ|файл|xlsx)|"
    r"(?:звіт|документ|файл|xlsx).*(?:прибуток|витрати?|дохід|грн|грн/га|площ)",
    re.IGNORECASE | re.UNICODE,
)

# ── Explicit doc-токени (перемагають vision) ─────────────────────────────────
_EXPLICIT_DOC_TOKEN_RE = re.compile(
    r"по\s+звіту|у\s+файлі|в\s+файлі|у\s+документі|в\s+документі|з\s+таблиц"
    r"|у\s+звіті|в\s+звіті|по\s+документу|з\s+документ|у\s+цьому\s+(?:файлі|звіті|документі)",
    re.IGNORECASE | re.UNICODE,
)

# ── Тригери що СКАСОВУЮТЬ doc-режим ──────────────────────────────────────────
_URL_RE = re.compile(r"https?://\S+", re.IGNORECASE)
_VISION_RE = re.compile(
    r"фото|картинк|зображенн|листя|плями|шкідник|хвороба|бур'ян|бурян"
    r"|рослин|гриб|гниль|хлороз|некроз|личинк|жук|кліщ|тля",
    re.IGNORECASE | re.UNICODE,
)
_ACTION_OPS_RE = re.compile(
    r"^(?:зроби|план|внеси|зафіксуй|перевір|порахуй|додай|видали|оновни|відкрий|нагадай)",
    re.IGNORECASE | re.UNICODE,
)
_WEB_INTENT_RE = re.compile(
    r"каталог|сайт|посиланн|переглянь\s+сторінк|вивч[иі]\s+каталог|знайди\s+на\s+сайт",
    re.IGNORECASE | re.UNICODE,
)

# ── v3.6: Fact-signal — числові запити без прив'язки до "звіту" ──────────────
_FACT_UNITS_RE = re.compile(
    r"грн|uah|₴|га\b|ha\b|%|грн/га|uah/ha|тис\.?|млн\.?|\d+\s*(?:грн|га|ha|%)",
    re.IGNORECASE | re.UNICODE,
)
_FACT_WORDS_RE = re.compile(
    r"прибуток|витрати?|виручка|дохід|маржа|площа|добрива|насіння|паливо|оренда|собівартість",
    re.IGNORECASE | re.UNICODE,
)

# ── v3.7: UX-фрази для заміни ────────────────────────────────────────────────
_DOC_AWARENESS_RE = re.compile(
    r"(так,\s*пам['\u2019]ятаю|не\s+бачу\s+його|не\s+бачу\s+перед\s+собою"
    r"|мені\s+(?:не\s+)?доступний\s+документ)",
    re.IGNORECASE | re.UNICODE,
)
_VISION_INTRO_RE = re.compile(
    r"^на\s+фото\s+видно",
    re.IGNORECASE | re.UNICODE,
)


def _is_doc_question(text: str) -> bool:
    """
    Rule-based: чи питання явно про документ/звіт.
    Explicit doc-токен перемагає vision-слова (скрін таблиці + caption).
    Fail-safe: будь-яка помилка → False.
    """
    try:
        t = text.strip()
        if _URL_RE.search(t):
            return False
        if _WEB_INTENT_RE.search(t):
            return False
        if _EXPLICIT_DOC_TOKEN_RE.search(t):
            return True
        if _VISION_RE.search(t):
            return False
        if _DOC_QUESTION_RE.search(t):
            return True
        if _DOC_FINANCIAL_RE.search(t):
            return True
        return False
    except Exception:
        return False


def _detect_domain(text: str, logger=None) -> str:
    """
    Визначає домен повідомлення.
    Повертає: "doc" | "vision" | "web" | "ops" | "general"

    Пріоритети:
      URL/web > explicit_doc_token > загальні doc-тригери > vision > ops > general
    Порожній текст (caption відсутній) → "vision".
    """
    try:
        t = text.strip()
        if not t:
            return "vision"
        if _URL_RE.search(t) or _WEB_INTENT_RE.search(t):
            return "web"
        if _EXPLICIT_DOC_TOKEN_RE.search(t):
            if _VISION_RE.search(t) and logger:
                try:
                    logger.info(
                        "AGX_STEPAN_METRIC domain_override from=vision to=doc reason=explicit_doc_tokens"
                    )
                except Exception:
                    pass
            return "doc"
        if _DOC_QUESTION_RE.search(t) or _DOC_FINANCIAL_RE.search(t):
            return "doc"
        if _VISION_RE.search(t):
            return "vision"
        if _ACTION_OPS_RE.search(t):
            return "ops"
        return "general"
    except Exception:
        return "general"


def detect_context_signals(text: str) -> dict:
    """
    v3.6: Повертає словник булевих сигналів для doc-mode gating.

    Ключі:
      has_explicit_doc_token: bool  — "по звіту", "у файлі" тощо
      has_doc_trigger:        bool  — загальні doc-тригери (звіт, документ)
      has_vision_trigger:     bool  — листя, шкідник, фото...
      has_url:                bool  — http(s)://...
      has_web_intent:         bool  — каталог, сайт...
      has_fact_signal:        bool  — числові одиниці або фін-слова
    """
    try:
        t = text.strip()
        return {
            "has_explicit_doc_token": bool(_EXPLICIT_DOC_TOKEN_RE.search(t)),
            "has_doc_trigger": bool(
                _DOC_QUESTION_RE.search(t) or _DOC_FINANCIAL_RE.search(t)
            ),
            "has_vision_trigger": bool(_VISION_RE.search(t)),
            "has_url": bool(_URL_RE.search(t)),
            "has_web_intent": bool(_WEB_INTENT_RE.search(t)),
            "has_fact_signal": bool(_FACT_UNITS_RE.search(t) or _FACT_WORDS_RE.search(t)),
        }
    except Exception:
        return {
            "has_explicit_doc_token": False, "has_doc_trigger": False,
            "has_vision_trigger": False, "has_url": False,
            "has_web_intent": False, "has_fact_signal": False,
        }


def build_mode_clarifier(text: str) -> str:
    """
    v3.6/v3.7: Одне контекстне уточнююче питання (без "!", без "будь ласка").

    URL    → "Ти про посилання чи про звіт?"
    vision → "Це про фото чи про цифри зі звіту?"
    facts  → "Це про конкретні цифри зі звіту?"
    інше   → "Йдеться про звіт чи про інше?"
    """
    try:
        t = text.strip()
        if _URL_RE.search(t):
            return "Ти про посилання чи про звіт?"
        if _VISION_RE.search(t):
            return "Це про фото чи про цифри зі звіту?"
        if _FACT_UNITS_RE.search(t) or _FACT_WORDS_RE.search(t):
            return "Це про конкретні цифри зі звіту?"
        return "Йдеться про звіт чи про інше?"
    except Exception:
        return "Йдеться про звіт чи про інше?"


def handle_doc_focus(sub: str, chat_id: str | None = None) -> dict:
    """
    /doc [on|off|status].

    /doc on     → doc_focus=True, TTL = DOC_FOCUS_TTL, cooldown скинутий
    /doc off    → doc_focus=False
    /doc status → поточний стан (focus, ttl_left, cooldown_left, active_doc_id, facts)
    """
    def _wrap(msg: str) -> dict:
        return {"ok": True, "message": msg}

    try:
        from crews.agromatrix_crew.session_context import (
            _STORE, DOC_FOCUS_TTL, is_doc_focus_active, load_session,
            is_doc_focus_cooldown_active,
        )
    except ImportError:
        return _wrap("session_context not available")

    if not chat_id:
        return _wrap("chat_id required for /doc command")

    now = time.time()

    if sub == "on":
        existing = _STORE.get(str(chat_id)) or {}
        existing["doc_focus"] = True
        existing["doc_focus_ts"] = now
        existing["doc_focus_cooldown_until"] = 0.0  # /doc on скидає cooldown
        _STORE[str(chat_id)] = existing
        doc_id = existing.get("active_doc_id") or "—"
        return _wrap(f"doc_focus=on. Документ: {str(doc_id)[:20]}. TTL={int(DOC_FOCUS_TTL)}с.")

    if sub == "off":
        existing = _STORE.get(str(chat_id)) or {}
        existing["doc_focus"] = False
        existing["doc_focus_ts"] = 0.0
        _STORE[str(chat_id)] = existing
        return _wrap("doc_focus=off. Степан відповідатиме без прив'язки до документа.")

    # status (default)
    session = load_session(str(chat_id))
    focus_active = is_doc_focus_active(session, now)
    cooldown_active = is_doc_focus_cooldown_active(session, now)
    doc_id = session.get("active_doc_id") or "—"
    doc_facts = session.get("doc_facts") or {}
    ttl_left = max(0.0, DOC_FOCUS_TTL - (now - (session.get("doc_focus_ts") or 0.0)))
    cooldown_left = max(0.0, (session.get("doc_focus_cooldown_until") or 0.0) - now)
    facts_keys = (
        ", ".join(k for k in doc_facts if k not in ("conflicts", "needs_recheck"))
        if doc_facts else "—"
    )
    cooldown_str = f" cooldown={int(cooldown_left)}с" if cooldown_active else ""
    return _wrap(
        f"doc_focus={'on' if focus_active else 'off'} "
        f"ttl_left={int(ttl_left)}с{cooldown_str} | "
        f"active_doc_id={str(doc_id)[:20]} | "
        f"facts=[{facts_keys}]"
    )
