from __future__ import annotations

import re


class DocsQuerySignals:
    _ENDPOINT_RE = re.compile(r"(?P<value>/(?:[a-z0-9_-]+|{[a-z0-9_]+})(?:/(?:[a-z0-9_-]+|{[a-z0-9_]+}))*)", re.IGNORECASE)
    _ENTITY_RE = re.compile(r"(?:entity|сущност[ьи]|модель|объект)\s+(?P<value>[A-Za-z][A-Za-z0-9_-]+(?:\s+[A-Za-z][A-Za-z0-9_-]+)?)", re.IGNORECASE)
    _COMPONENT_RE = re.compile(r"(?:component|компонент|service|module|модул[ья])\s+(?P<value>[A-Za-z][A-Za-z0-9_-]+)", re.IGNORECASE)
    _WORKFLOW_RE = re.compile(r"(?:workflow|сценарий|процесс|overview)\s+(?P<value>[A-Za-zА-Яа-я0-9_-]+)", re.IGNORECASE)
    _DOC_RE = re.compile(r"(?:document|документ|documentation|документац[ияи])\s+(?P<value>[A-Za-zА-Яа-я0-9_.-]+)", re.IGNORECASE)
    _CAMEL_RE = re.compile(r"\b(?P<value>[A-Z][A-Za-z0-9]+(?:Manager|Worker|Channel|Service|Module|Status|Health)|[A-Z][a-z0-9]+(?:[A-Z][A-Za-z0-9]+)+)\b")
    _QUOTED_RE = re.compile(r"[\"'«“](?P<value>[^\"'»”]{2,})[\"'»”]")
    _MULTIWORD_RE = re.compile(r"\b(runtime health|worker status|control plane)\b", re.IGNORECASE)

    def detect_anchor(self, raw: str) -> tuple[str, str | None]:
        text = raw or ""
        anchor_patterns = [
            ("entity", self._ENTITY_RE),
            ("component", self._COMPONENT_RE),
            ("workflow", self._WORKFLOW_RE),
            ("document", self._DOC_RE),
        ]
        if not any(ext in text.lower() for ext in (".py", ".ts", ".js", ".java", ".go", ".rb")):
            anchor_patterns.insert(0, ("endpoint", self._ENDPOINT_RE))
        for anchor_type, pattern in anchor_patterns:
            match = pattern.search(text)
            if match:
                return anchor_type, str(match.group("value")).strip()
        if any(marker in text.lower() for marker in ("api", "endpoint", "topic", "тема")):
            return "topic", None
        return "none", None

    def has_docs_anchor(self, raw: str) -> bool:
        anchor_type, _ = self.detect_anchor(raw)
        return anchor_type != "none"

    def query_entity_candidates(self, raw: str) -> list[str]:
        text = raw or ""
        values: list[str] = []
        for match in self._ENTITY_RE.finditer(text):
            values.append(match.group("value").strip())
        for match in self._CAMEL_RE.finditer(text):
            values.append(match.group("value").strip())
        for match in self._MULTIWORD_RE.finditer(text):
            values.append(match.group(1).strip())
        return self._dedupe(values)

    def query_anchor_candidates(self, raw: str) -> list[str]:
        text = raw or ""
        values: list[str] = []
        for match in self._ENDPOINT_RE.finditer(text):
            values.append(match.group("value").strip())
        for match in self._CAMEL_RE.finditer(text):
            values.append(match.group("value").strip())
        for match in self._QUOTED_RE.finditer(text):
            values.append(match.group("value").strip())
        return self._dedupe(values)

    def has_component_like_token(self, raw: str) -> bool:
        return bool(self._CAMEL_RE.search(raw or ""))

    def _dedupe(self, values: list[str]) -> list[str]:
        result: list[str] = []
        seen: set[str] = set()
        for value in values:
            normalized = value.strip()
            if not normalized:
                continue
            key = normalized.lower()
            if key in seen:
                continue
            seen.add(key)
            result.append(normalized)
        return result
