"""Inspect an installed .pyi for S06 declarations WITHOUT importing or executing it.

An interface declaration is not an encoder capability or successful live call.
Missing names are reported as NOT DECLARED HERE, not as absent in all versions.
"""
import argparse
import ast
import hashlib
import json
from pathlib import Path

QUERIES = {
    "Project": ("GetRenderPresetList", "LoadRenderPreset", "GetRenderFormats", "GetRenderCodecs",
                "GetCurrentRenderFormatAndCodec", "SetCurrentRenderFormatAndCodec", "GetCurrentRenderMode",
                "SetCurrentRenderMode", "GetRenderResolutions", "SetRenderSettings", "GetRenderSettings",
                "GetSettings", "SetSettings"),
    "RenderSettings": ("FormatWidth", "FormatHeight", "ResolutionWidth", "ResolutionHeight",
                       "TargetDir", "CustomName", "UseUniqueFilenames", "UniqueFilenameStyle",
                       "VideoQuality", "Format", "VideoCodec", "IndividualClips", "AudioBitrate"),
}


def audit(path):
    with Path(path).open("rb") as f:
        raw = f.read(2 * 1024 * 1024 + 1)
    if len(raw) > 2 * 1024 * 1024:
        raise ValueError("Document exceeds the 2 MiB tutorial bound")
    tree = ast.parse(raw.decode("utf-8-sig"))
    classes = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)}
    if not all(name in classes for name in QUERIES):
        raise ValueError("Expected Project and RenderSettings classes in this interface document")
    result = {}
    for owner, names in QUERIES.items():
        found = {}
        for node in classes[owner].body:
            if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
                found[node.name] = {"line": node.lineno, "kind": "method", "arguments": ast.unparse(node.args)}
            elif isinstance(node, ast.AnnAssign) and isinstance(node.target, ast.Name):
                found[node.target.id] = {"line": node.lineno, "kind": "field", "type": ast.unparse(node.annotation)}
        result[owner] = {name: found.get(name, {"status": "not_declared_here"}) for name in names}
    return {"document_sha256": hashlib.sha256(raw).hexdigest(), "declarations": result,
            "live_verified": False, "scope": "This file only; not native execution or encoder support"}


def main():
    p = argparse.ArgumentParser(description=__doc__)
    p.add_argument("interface_file", type=Path)
    a = p.parse_args()
    try:
        print(json.dumps(audit(a.interface_file), ensure_ascii=False, indent=2))
    except (OSError, UnicodeError, ValueError, SyntaxError, RecursionError) as exc:
        print(json.dumps({"status": "audit_failed", "error": type(exc).__name__ + ": " + str(exc)}))
        return 2
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
