#!/usr/bin/env python3
"""
Mem0 Documentation Search Agent (Mintlify-based)
On-demand search tool for querying Mem0 documentation without storing content locally.

This tool leverages Mintlify's documentation structure to perform just-in-time
retrieval of technical information from docs.mem0.ai.

Usage:
    python mem0_doc_search.py --query "how to add graph memory"
    python mem0_doc_search.py --query "filter syntax for categories"
    python mem0_doc_search.py --page "/platform/features/graph-memory"
    python mem0_doc_search.py --index
    python mem0_doc_search.py --query "webhook events" --section platform

Purpose:
    - Avoid bloating local context with full documentation
    - Enable just-in-time retrieval of technical details
    - Query specific documentation pages on demand
    - Search across the full Mem0 documentation site
"""

import argparse
import json
import sys
import urllib.error
import urllib.parse
import urllib.request

DOCS_BASE = "https://docs.mem0.ai"
SEARCH_ENDPOINT = f"{DOCS_BASE}/api/search"
LLMS_INDEX = f"{DOCS_BASE}/llms.txt"

# Known documentation sections for targeted retrieval
SECTION_MAP = {
    "platform": [
        "/platform/overview",
        "/platform/quickstart",
        "/platform/features",
        "/platform/features/graph-memory",
        "/platform/features/selective-memory",
        "/platform/features/custom-categories",
        "/platform/features/v2-memory-filters",
        "/platform/features/async-client",
        "/platform/features/webhooks",
        "/platform/features/multimodal-support",
    ],
    "api": [
        "/api-reference/memory/add-memories",
        "/api-reference/memory/v2-search-memories",
        "/api-reference/memory/v2-get-memories",
        "/api-reference/memory/get-memory",
        "/api-reference/memory/update-memory",
        "/api-reference/memory/delete-memory",
    ],
    "open-source": [
        "/open-source/overview",
        "/open-source/python-quickstart",
        "/open-source/node-quickstart",
        "/open-source/features",
        "/open-source/features/graph-memory",
        "/open-source/features/rest-api",
        "/open-source/configure-components",
    ],
    "openmemory": [
        "/openmemory/overview",
        "/openmemory/quickstart",
    ],
    "sdks": [
        "/sdks/python",
        "/sdks/js",
    ],
    "integrations": [
        "/integrations",
    ],
}


def fetch_url(url: str) -> str:
    """Fetch content from a URL."""
    req = urllib.request.Request(url, headers={"User-Agent": "Mem0DocSearchAgent/1.0"})
    try:
        with urllib.request.urlopen(req, timeout=15) as resp:
            return resp.read().decode("utf-8")
    except urllib.error.HTTPError as e:
        return f"HTTP Error {e.code}: {e.reason}"
    except urllib.error.URLError as e:
        return f"URL Error: {e.reason}"


def search_docs(query: str, section: str | None = None) -> dict:
    """
    Search Mem0 documentation using Mintlify's search API.
    Falls back to the llms.txt index for keyword matching if the API is unavailable.
    """
    # Try Mintlify search API first
    params = urllib.parse.urlencode({"query": query})
    search_url = f"{SEARCH_ENDPOINT}?{params}"

    try:
        result = fetch_url(search_url)
        data = json.loads(result)
        if isinstance(data, dict) and data.get("results"):
            results = data["results"]
            if section and section in SECTION_MAP:
                section_paths = SECTION_MAP[section]
                results = [r for r in results if any(r.get("url", "").startswith(p) for p in section_paths)]
            return {"source": "mintlify_search", "results": results}
    except (json.JSONDecodeError, Exception):
        pass

    # Fallback: search llms.txt index for matching URLs
    index_content = fetch_url(LLMS_INDEX)
    query_lower = query.lower()
    matching_urls = []

    for line in index_content.splitlines():
        line = line.strip()
        if not line or line.startswith("#"):
            continue
        if query_lower in line.lower():
            matching_urls.append(line)

    if section and section in SECTION_MAP:
        section_paths = SECTION_MAP[section]
        matching_urls = [u for u in matching_urls if any(p in u for p in section_paths)]

    return {
        "source": "llms_txt_index",
        "query": query,
        "matching_urls": matching_urls[:20],
        "suggestion": "Fetch specific URLs for detailed content",
    }


def fetch_page(page_path: str) -> dict:
    """Fetch a specific documentation page."""
    url = f"{DOCS_BASE}{page_path}" if page_path.startswith("/") else page_path
    content = fetch_url(url)
    return {"url": url, "content": content[:10000], "truncated": len(content) > 10000}


def get_index() -> dict:
    """Fetch the full documentation index from llms.txt."""
    content = fetch_url(LLMS_INDEX)
    urls = [line.strip() for line in content.splitlines() if line.strip() and not line.startswith("#")]
    return {"total_pages": len(urls), "urls": urls, "sections": list(SECTION_MAP.keys())}


def list_section(section: str) -> dict:
    """List all known pages in a documentation section."""
    if section not in SECTION_MAP:
        return {"error": f"Unknown section: {section}", "available": list(SECTION_MAP.keys())}
    return {
        "section": section,
        "pages": [f"{DOCS_BASE}{p}" for p in SECTION_MAP[section]],
    }


def main():
    parser = argparse.ArgumentParser(description="Search Mem0 documentation on demand")
    parser.add_argument("--query", help="Search query for documentation")
    parser.add_argument("--page", help="Fetch a specific page path (e.g., /platform/features/graph-memory)")
    parser.add_argument("--index", action="store_true", help="Show full documentation index")
    parser.add_argument("--section", help="Filter by section or list section pages")
    parser.add_argument("--json", action="store_true", help="Output as JSON")

    args = parser.parse_args()

    if args.index:
        result = get_index()
    elif args.section and not args.query:
        result = list_section(args.section)
    elif args.page:
        result = fetch_page(args.page)
    elif args.query:
        result = search_docs(args.query, section=args.section)
    else:
        parser.print_help()
        sys.exit(1)

    if args.json:
        print(json.dumps(result, indent=2))
    else:
        if isinstance(result, dict):
            if "results" in result:
                print(f"Source: {result.get('source', 'unknown')}")
                for r in result["results"]:
                    print(f"  - {r.get('title', 'N/A')}: {r.get('url', 'N/A')}")
                    if r.get("description"):
                        print(f"    {r['description'][:200]}")
            elif "matching_urls" in result:
                print(f"Source: {result['source']}")
                print(f"Query: {result['query']}")
                for url in result["matching_urls"]:
                    print(f"  - {url}")
                if result.get("suggestion"):
                    print(f"\n{result['suggestion']}")
            elif "urls" in result:
                print(f"Total documentation pages: {result['total_pages']}")
                print(f"Sections: {', '.join(result['sections'])}")
                for url in result["urls"][:30]:
                    print(f"  - {url}")
                if result["total_pages"] > 30:
                    print(f"  ... and {result['total_pages'] - 30} more")
            elif "pages" in result:
                print(f"Section: {result['section']}")
                for page in result["pages"]:
                    print(f"  - {page}")
            elif "content" in result:
                print(f"URL: {result['url']}")
                if result.get("truncated"):
                    print("[Content truncated to 10000 chars]")
                print(result["content"])
            elif "error" in result:
                print(f"Error: {result['error']}")
                if result.get("available"):
                    print(f"Available sections: {', '.join(result['available'])}")
            else:
                print(json.dumps(result, indent=2))


if __name__ == "__main__":
    main()
