"""Build an in-memory DOCS scope index from D1/D3 catalog rows (no chunk retrieval).

Parses metadata from ``D1_DOCUMENT_CATALOG`` and ``D3_ENTITY_CATALOG`` rows produced by the
existing RAG indexer—no additional layers or chunk scans.
"""

from __future__ import annotations

import re
from dataclasses import dataclass, field


def _norm_text(value: object) -> str:
    return re.sub(r"\s+", " ", str(value or "").strip().lower())


def _split_multi(value: object) -> list[str]:
    if value is None:
        return []
    if isinstance(value, list):
        raw = value
    else:
        raw = re.split(r"[;,|]", str(value))
    out: list[str] = []
    for item in raw:
        s = str(item).strip()
        if s:
            out.append(s)
    return out


@dataclass(slots=True)
class DocsScopeCatalog:
    """Flattened terms from D1_DOCUMENT_CATALOG and D3_ENTITY_CATALOG for lexical grounding."""

    domain_values: set[str] = field(default_factory=set)
    subdomain_pairs: list[tuple[str, str]] = field(default_factory=list)  # (domain, subdomain)
    entity_records: list[dict[str, object]] = field(default_factory=list)
    api_records: list[dict[str, object]] = field(default_factory=list)


def build_docs_scope_catalog(rows: list[dict]) -> DocsScopeCatalog:
    """Derive searchable terms from catalog layers only (existing RAG index rows)."""
    catalog = DocsScopeCatalog()
    for row in rows:
        layer = str(row.get("layer") or "")
        meta = row.get("metadata")
        if not isinstance(meta, dict):
            meta = {}
        path = str(row.get("path") or "")
        title = str(row.get("title") or "")
        content = str(row.get("content") or "")

        if layer == "D1_DOCUMENT_CATALOG":
            _ingest_d1_row(catalog, path=path, title=title, content=content, metadata=meta)
        elif layer == "D3_ENTITY_CATALOG":
            _ingest_d3_row(catalog, path=path, title=title, metadata=meta)

    return catalog


def _ingest_d1_row(
    catalog: DocsScopeCatalog,
    *,
    path: str,
    title: str,
    content: str,
    metadata: dict,
) -> None:
    doc_type = _norm_text(metadata.get("type") or metadata.get("doc_type"))
    domain = _norm_text(metadata.get("domain"))
    subdomain = _norm_text(metadata.get("subdomain"))
    name = _norm_text(metadata.get("name"))
    summary = _norm_text(metadata.get("summary_text"))
    endpoint = _norm_text(metadata.get("endpoint"))

    entities = [_norm_text(e) for e in _split_multi(metadata.get("entities"))]
    tags = [_norm_text(t) for t in _split_multi(metadata.get("tags"))]

    if domain:
        catalog.domain_values.add(domain)
    if domain and subdomain:
        catalog.subdomain_pairs.append((domain, subdomain))

    blob = " ".join(x for x in (name, title, summary, content) if x)
    for ent in entities:
        if ent:
            catalog.entity_records.append(
                {
                    "name": ent,
                    "domain": domain or None,
                    "subdomain": subdomain or None,
                    "source_layer": "D1_DOCUMENT_CATALOG",
                    "path": path,
                    "blob": blob,
                }
            )
    for tag in tags:
        if tag and len(tag) >= 3:
            catalog.entity_records.append(
                {
                    "name": tag,
                    "domain": domain or None,
                    "subdomain": subdomain or None,
                    "source_layer": "D1_DOCUMENT_CATALOG",
                    "path": path,
                    "blob": blob,
                }
            )

    is_api_method = doc_type == "api_method" or "api_method" in path.lower()
    if is_api_method or endpoint:
        ep = endpoint or _endpoint_from_title(title)
        if ep:
            catalog.api_records.append(
                {
                    "endpoint": ep,
                    "domain": domain or None,
                    "source_layer": "D1_DOCUMENT_CATALOG",
                    "path": path,
                    "title": title,
                }
            )


def _ingest_d3_row(
    catalog: DocsScopeCatalog,
    *,
    path: str,
    title: str,
    metadata: dict,
) -> None:
    entity_name = str(metadata.get("entity_name") or "").strip()
    domain = _norm_text(metadata.get("domain"))
    subdomain = _norm_text(metadata.get("subdomain"))
    module = _norm_text(metadata.get("module"))
    source_path = str(metadata.get("source_path") or "").strip()
    tags = [_norm_text(t) for t in _split_multi(metadata.get("tags"))]

    if domain:
        catalog.domain_values.add(domain)
    if domain and subdomain:
        catalog.subdomain_pairs.append((domain, subdomain))

    blob = " ".join(
        _norm_text(x)
        for x in (entity_name, title, module, source_path, " ".join(tags))
        if x
    )
    if entity_name:
        catalog.entity_records.append(
            {
                "name": _norm_text(entity_name),
                "domain": domain or None,
                "subdomain": subdomain or None,
                "module": module or None,
                "source_layer": "D3_ENTITY_CATALOG",
                "path": path or source_path,
                "blob": blob,
            }
        )


def _endpoint_from_title(title: str) -> str:
    t = str(title or "").strip()
    if not t:
        return ""
    upper = t.upper()
    for method in ("GET ", "POST ", "PUT ", "PATCH ", "DELETE "):
        if method in upper:
            idx = upper.index(method)
            rest = t[idx:].split()
            if len(rest) >= 2 and rest[1].startswith("/"):
                return _norm_text(rest[1])
    m = re.search(r"(\/[a-z0-9_./{}-]+)", t, re.IGNORECASE)
    return _norm_text(m.group(1)) if m else ""
