"""Индекс метаданных RAG-строк для подбора кандидатов по маршруту v2."""

from __future__ import annotations

import re
from collections import defaultdict

from app.core.agent.utils.process_v2.models import V2RouteResult


class DocsMetadataLookupIndex:
    def __init__(self, rows: list[dict]) -> None:
        self._rows_by_path: dict[str, dict] = {}
        self._rows_by_basename: dict[str, list[dict]] = defaultdict(list)
        self._rows_by_slug: dict[str, list[dict]] = defaultdict(list)
        self._rows_by_title_token: dict[str, list[dict]] = defaultdict(list)
        self._rows_by_compact: dict[str, list[dict]] = defaultdict(list)
        for row in rows:
            path = str(row.get("path") or "").strip()
            if not path or path in self._rows_by_path:
                continue
            self._rows_by_path[path] = row
            basename = path.split("/")[-1].lower()
            slug = basename.removesuffix(".md").removesuffix(".yaml").removesuffix(".yml")
            self._rows_by_basename[basename].append(row)
            self._rows_by_slug[slug].append(row)
            self._rows_by_compact[self._compact(slug)].append(row)
            title = str(row.get("title") or "").lower()
            for token in self._tokens(title):
                self._rows_by_title_token[token].append(row)
            self._rows_by_compact[self._compact(title)].append(row)
            entity_name = str(dict(row.get("metadata") or {}).get("entity_name") or "").lower()
            if entity_name:
                self._rows_by_compact[self._compact(entity_name)].append(row)

    def lookup(self, route: V2RouteResult) -> list[dict]:
        candidates: list[dict] = []
        seen: set[str] = set()
        for path in route.anchors.target_doc_hints:
            self._append(candidates, seen, self._rows_by_path.get(path))
        lookup_tokens = list(route.target_terms) + list(route.anchors.matched_aliases) + list(route.anchors.endpoint_paths)
        for token in self._tokens(" ".join(lookup_tokens)):
            for bucket in (
                self._rows_by_basename.get(token, []),
                self._rows_by_slug.get(token, []),
                self._rows_by_title_token.get(token, []),
            ):
                for row in bucket:
                    self._append(candidates, seen, row)
        for compact in {self._compact(item) for item in lookup_tokens if item}:
            for row in self._rows_by_compact.get(compact, []):
                self._append(candidates, seen, row)
        return candidates

    def _append(self, items: list[dict], seen: set[str], row: dict | None) -> None:
        if row is None:
            return
        path = str(row.get("path") or "").strip()
        if not path or path in seen:
            return
        seen.add(path)
        items.append(row)

    def _tokens(self, value: str) -> list[str]:
        return [token for token in re.split(r"[^a-zA-Zа-яА-Я0-9]+", str(value or "").lower()) if len(token) >= 3]

    def _compact(self, value: str) -> str:
        return "".join(self._tokens(value))
