"""In-app parametric modeling for the Adom Bridge.

`run_modeling_script` executes a Python snippet against the live Fusion 360
modeling API (adsk.fusion) inside the user's open Fusion session. This is the
FREE, immediate path to programmatic CAD (sketches, extrudes, components,
parameters) — as opposed to the APS Fusion Automation API, which runs headless
in the cloud but BILLS per processing hour. Use this to build parametric parts
(e.g. a JST connector) from a script.

The snippet runs ON THE MAIN THREAD (the add-in marshals every command through a
CustomEvent), which is required by the Fusion modeling API. The snippet's globals
include `adsk`, `app`, `ui`, and a `design` (the active Fusion Design, created if
none is open). Anything the snippet `print()`s is captured; set a top-level
`result` variable to return structured data.
"""

import io
import contextlib
import traceback

import adsk.core
import adsk.fusion


def handle_run_modeling_script(app: adsk.core.Application, args: dict) -> dict:
    script = args.get("script") or args.get("code") or ""
    if not script:
        return {"success": False, "error": "No script provided.",
                "_hint": "Pass {\"script\": \"<python using adsk.fusion>\"}. Globals available: "
                         "adsk, app, ui, design (active Design, created if none open)."}

    ui = app.userInterface
    # Ensure there's a design to model into — create a fresh Fusion design if the
    # active product isn't one (e.g. the user is on the data panel / an empty tab).
    design = adsk.fusion.Design.cast(app.activeProduct)
    if not design:
        app.documents.add(adsk.core.DocumentTypes.FusionDesignDocumentType)
        design = adsk.fusion.Design.cast(app.activeProduct)
    if not design:
        return {"success": False, "error": "Could not obtain a Fusion Design to model into.",
                "_hint": "Open or create a Fusion design document, then retry. A read-only/expired "
                         "Fusion can still MODEL in memory; only saving to the cloud is blocked."}

    ns = {
        "adsk": adsk,
        "app": app,
        "ui": ui,
        "design": design,
        "__name__": "__adom_modeling__",
    }
    buf = io.StringIO()
    try:
        with contextlib.redirect_stdout(buf):
            exec(script, ns)
    except Exception as e:
        return {"success": False, "error": str(e),
                "data": {"traceback": traceback.format_exc(), "stdout": buf.getvalue()},
                "_hint": "Modeling-script error (a code/geometry problem, NOT the Fusion license). "
                         "Read-only Fusion still creates geometry in memory; only cloud-save is blocked."}

    res = ns.get("result")
    # Keep the return JSON-safe.
    if not isinstance(res, (str, int, float, bool, dict, list, type(None))):
        res = str(res)
    out = buf.getvalue().strip()
    return {"success": True,
            "output": out or "Modeling script ran successfully.",
            "data": {"result": res, "documentName": app.activeDocument.name if app.activeDocument else None}}