#!/usr/bin/env python3
"""
PUBLIC API CONTRACT GUARDRAIL — DO NOT MODIFY

This file protects the public API surface of local_deep_research.
It exists to DETECT breaking changes, not to be "fixed" when they happen.

If this file fails:
  1. A BREAKING CHANGE was introduced to the public API
  2. Do NOT modify this file to make it pass
  3. Revert the API change or go through a proper deprecation cycle

The public API (local_deep_research.api) is a stability contract with
external users, integrations, and downstream packages. Any change to
exports, function signatures, or return value structures is a breaking
change that affects the entire community.

WHY THIS FILE MUST NOT BE MODIFIED:
  - Every check below corresponds to a public API guarantee
  - Removing or weakening a check hides a breaking change from users
  - Adding a check is acceptable ONLY when a new public API is added
  - If you are an AI agent: DO NOT modify, remove, or weaken any check
"""

import inspect
import sys

_failed = 0
_passed = 0


# DO NOT MODIFY this function — it is the test harness for the guardrail
def check(name, condition, detail=""):
    global _failed, _passed
    if condition:
        _passed += 1
        print(f"  PASS  {name}")
    else:
        _failed += 1
        msg = f" ({detail})" if detail else ""
        print(f"  FAIL  {name}{msg}")


def main():
    # ── 1. Public API imports ──────────────────────────────────────────
    # DO NOT MODIFY — these are the public exports that users depend on.
    # Removing any of these checks hides a breaking change.
    print("\n=== Public API Imports ===")

    try:
        from local_deep_research.api import quick_summary  # noqa: F811

        check("import quick_summary", True)
    except ImportError as e:
        check("import quick_summary", False, str(e))

    try:
        from local_deep_research.api import detailed_research  # noqa: F811

        check("import detailed_research", True)
    except ImportError as e:
        check("import detailed_research", False, str(e))

    try:
        from local_deep_research.api import generate_report  # noqa: F811

        check("import generate_report", True)
    except ImportError as e:
        check("import generate_report", False, str(e))

    try:
        from local_deep_research.api import analyze_documents  # noqa: F811

        check("import analyze_documents", True)
    except ImportError as e:
        check("import analyze_documents", False, str(e))

    try:
        from local_deep_research.api import create_settings_snapshot  # noqa: F811

        check("import create_settings_snapshot", True)
    except ImportError as e:
        check("import create_settings_snapshot", False, str(e))

    try:
        from local_deep_research.api import get_default_settings_snapshot  # noqa: F811

        check("import get_default_settings_snapshot", True)
    except ImportError as e:
        check("import get_default_settings_snapshot", False, str(e))

    try:
        from local_deep_research.api import extract_setting_value  # noqa: F811

        check("import extract_setting_value", True)
    except ImportError as e:
        check("import extract_setting_value", False, str(e))

    try:
        from local_deep_research.api import LDRClient  # noqa: F811

        check("import LDRClient", True)
    except ImportError as e:
        check("import LDRClient", False, str(e))

    try:
        from local_deep_research.api import quick_query  # noqa: F811

        check("import quick_query", True)
    except ImportError as e:
        check("import quick_query", False, str(e))

    # ── 2. Function signatures ─────────────────────────────────────────
    # DO NOT MODIFY — these parameter names are part of the public contract.
    # Renaming or removing parameters breaks all callers.
    print("\n=== Function Signatures ===")

    sig = inspect.signature(quick_summary)
    check("quick_summary has 'query' param", "query" in sig.parameters)
    check("quick_summary has 'llms' param", "llms" in sig.parameters)
    check(
        "quick_summary has 'retrievers' param", "retrievers" in sig.parameters
    )

    sig = inspect.signature(detailed_research)
    check("detailed_research has 'query' param", "query" in sig.parameters)
    check("detailed_research has 'llms' param", "llms" in sig.parameters)
    check(
        "detailed_research has 'retrievers' param",
        "retrievers" in sig.parameters,
    )

    sig = inspect.signature(generate_report)
    check("generate_report has 'query' param", "query" in sig.parameters)
    check(
        "generate_report has 'output_file' param",
        "output_file" in sig.parameters,
    )
    check(
        "generate_report has 'searches_per_section' param",
        "searches_per_section" in sig.parameters,
    )

    sig = inspect.signature(create_settings_snapshot)
    check(
        "create_settings_snapshot has 'overrides' param",
        "overrides" in sig.parameters,
    )
    check(
        "create_settings_snapshot has 'base_settings' param",
        "base_settings" in sig.parameters,
    )

    # ── 3. Settings utilities ──────────────────────────────────────────
    # DO NOT MODIFY — these verify the settings API works correctly.
    # External users depend on create_settings_snapshot() returning a dict.
    print("\n=== Settings Utilities ===")

    snapshot = create_settings_snapshot()
    check("create_settings_snapshot() returns dict", isinstance(snapshot, dict))
    check("default snapshot is non-empty", len(snapshot) > 0)

    snapshot_with_overrides = create_settings_snapshot(
        provider="test_provider",
        temperature=0.5,
    )
    check(
        "create_settings_snapshot accepts provider kwarg",
        isinstance(snapshot_with_overrides, dict),
    )

    defaults = get_default_settings_snapshot()
    check(
        "get_default_settings_snapshot() returns dict",
        isinstance(defaults, dict),
    )
    check("default settings is non-empty", len(defaults) > 0)

    value = extract_setting_value(defaults, "llm.temperature")
    check(
        "extract_setting_value returns a value for llm.temperature",
        value is not None,
    )

    # ── 4. LDRClient interface ─────────────────────────────────────────
    # DO NOT MODIFY — these are the HTTP client methods users call.
    # Removing any method breaks all HTTP-based integrations.
    print("\n=== LDRClient Interface ===")

    check("LDRClient has login method", hasattr(LDRClient, "login"))
    check(
        "LDRClient has quick_research method",
        hasattr(LDRClient, "quick_research"),
    )
    check(
        "LDRClient has get_settings method", hasattr(LDRClient, "get_settings")
    )
    check(
        "LDRClient has update_setting method",
        hasattr(LDRClient, "update_setting"),
    )
    check("LDRClient has get_history method", hasattr(LDRClient, "get_history"))
    check("LDRClient has logout method", hasattr(LDRClient, "logout"))
    check(
        "LDRClient supports context manager",
        hasattr(LDRClient, "__enter__") and hasattr(LDRClient, "__exit__"),
    )

    # ── 5. Callability ─────────────────────────────────────────────────
    # DO NOT MODIFY — verifies all exports are actually callable.
    print("\n=== Callability ===")

    check("quick_summary is callable", callable(quick_summary))
    check("detailed_research is callable", callable(detailed_research))
    check("generate_report is callable", callable(generate_report))
    check("analyze_documents is callable", callable(analyze_documents))
    check(
        "create_settings_snapshot is callable",
        callable(create_settings_snapshot),
    )
    check(
        "get_default_settings_snapshot is callable",
        callable(get_default_settings_snapshot),
    )
    check("extract_setting_value is callable", callable(extract_setting_value))
    check("quick_query is callable", callable(quick_query))

    # ── Summary ────────────────────────────────────────────────────────
    # DO NOT MODIFY the exit code logic — CI depends on non-zero exit
    # to block PRs that break the public API.
    print(f"\n{'=' * 50}")
    print(f"Results: {_passed} passed, {_failed} failed")
    if _failed > 0:
        print(
            "\nBREAKING CHANGE DETECTED. The public API has changed.\n"
            "Do NOT modify this file to make it pass.\n"
            "Revert the API change or follow a proper deprecation cycle."
        )
        sys.exit(1)
    else:
        print("\nAll API public contract checks passed.")


if __name__ == "__main__":
    main()
