"""Verify that the published MDX signatures match the actual SDK code defaults.

Parses the JSX-encoded signature blocks in the generated MDX and compares
default values against the Python code. Catches regressions where the doc
renderer produces a different default than the code.
"""

from __future__ import annotations

import inspect
import re
from pathlib import Path

import pytest

from _doc_gen.catalogue import PUBLIC_METHODS, _sync_api_class_for_slug

# Layout: PAIR/goodmem/clients/v2/python/tests/ (here) and PAIR/goodmem-docs/
_V2_DIR = Path(__file__).parent.parent.parent  # clients/v2/
DOCS_DIR = (_V2_DIR / ".." / ".." / ".." / "goodmem-docs" / "content" / "docs" / "reference" / "sdk" / "v2" / "python").resolve()


def _extract_mdx_defaults(mdx_path: Path) -> dict[str, dict[str, str]]:
    """Extract {method: {param: default_str}} from JSX signature blocks."""
    text = mdx_path.read_text()
    results: dict[str, dict[str, str]] = {}

    # Find each method's signature block: <div id="method_name" ...>...</div>
    for div_match in re.finditer(r'<div id="([^"]+)"[^>]*>(.+?)</div>', text, re.DOTALL):
        method_name = div_match.group(1)
        sig_html = div_match.group(2)

        # The JSX encodes params as: {"param_name"} ... {": "} ... {" = default"}
        # Extract all {"text"} tokens in order, then pair param names with defaults.
        tokens = re.findall(r'\{"([^"]+)"\}', sig_html)
        params: dict[str, str] = {}
        i = 0
        while i < len(tokens):
            tok = tokens[i]
            # A param name is a word token followed by ": " then type then " = default"
            if re.match(r'^\w+$', tok) and tok not in ("*", ","):
                # Look ahead for " = X" within the next few tokens
                for j in range(i + 1, min(i + 8, len(tokens))):
                    if tokens[j].startswith(" = "):
                        params[tok] = tokens[j][3:]  # strip " = " prefix
                        break
                    # Stop if we hit another param name (word followed by ": ")
                    if (re.match(r'^\w+$', tokens[j]) and tokens[j] not in ("*", ",")
                            and j + 1 < len(tokens) and tokens[j + 1] == ": "):
                        break
            i += 1
        if params:
            results[method_name] = params

    return results


# Params where we know the code has a non-None default that must appear in the MDX
_MUST_MATCH = [
    ("memories", "get", "include_content", False),
    ("memories", "get", "include_processing_history", False),
    ("memories", "list", "include_content", False),
    ("memories", "list", "include_processing_history", False),
    ("spaces", "create", "public_read", False),
    ("memories", "retrieve", "chronological_resort", True),
    ("memories", "retrieve", "fetch_memory", True),
    ("memories", "retrieve", "fetch_memory_content", False),
    ("memories", "retrieve", "gen_token_budget", 512),
    ("memories", "retrieve", "llm_temp", 0.3),
    ("memories", "retrieve", "max_results", 10),
    ("memories", "retrieve", "stream", True),
]


class TestMDXDefaultsMatchCode:
    """Published MDX signature defaults must match the actual code."""

    @pytest.mark.parametrize(
        "slug,method,param,expected",
        _MUST_MATCH,
        ids=[f"{s}.{m}.{p}" for s, m, p, _ in _MUST_MATCH],
    )
    def test_mdx_default(self, slug, method, param, expected):
        mdx_path = DOCS_DIR / f"{slug}.mdx"
        if not mdx_path.exists():
            pytest.skip(f"{mdx_path} not found — run doc_gen.sh first")

        method_defaults = _extract_mdx_defaults(mdx_path)
        params = method_defaults.get(method, {})

        assert param in params, (
            f"{slug}.{method}: param '{param}' not found in MDX signature"
        )
        assert str(params[param]) == str(expected), (
            f"{slug}.{method}.{param}: MDX shows '= {params[param]}', "
            f"code has '= {expected}'"
        )
