"""Paste into Rhino 8 Grasshopper Python 3, then create named inputs below.
Inputs (Item unless specified): RepoPath, BaseUrl, ApiKey, ProjectId, Filename,
Revision, SelectedIds (List GUID strings), NestedPaths (List JSON arrays of GUIDs),
OutputDirectory, IdempotencyKey, AllowProxy, Export, Start, Poll, Download, Upload,
Cancel, ExportChildren (optional boolean, defaults true). Outputs: JobId, Status, Report, PackagePath, IfcPath, Model.
All actions are rising-edge triggers. Toggle false before triggering again.
No bake, deletion, selection-all, document-unit changes or automatic publication.
"""

import sys, os, json, uuid
from pathlib import Path
import Rhino, scriptcontext as sc

if str(RepoPath) not in sys.path:
    sys.path.insert(0, str(RepoPath))
from adapters.rhino_to_ifc.rhino import extract
from adapters.rhino_to_ifc.client import Client

component_id = str(ghenv.Component.InstanceGuid)
sticky_key = "ontologic:rhino-export:" + component_id
state = sc.sticky.setdefault(
    sticky_key,
    {
        "edges": {},
        "job": None,
        "package": None,
        "ifc": None,
        "model": None,
        "report": None,
        "status": "Idle",
    },
)


def triggered(name):
    current = bool(globals().get(name, False))
    previous = state["edges"].get(name, False)
    state["edges"][name] = current
    return current and not previous


# Capture all edges every solve, even if an earlier operation fails.
events = {
    name: triggered(name)
    for name in ("Export", "Start", "Poll", "Download", "Upload", "Cancel")
}
try:
    if events["Export"]:
        directory = Path(str(OutputDirectory)).resolve()
        directory.mkdir(parents=True, exist_ok=True)
        selection = [str(v) for v in (SelectedIds or [])] + [
            json.loads(str(v)) for v in (NestedPaths or [])
        ]
        package = directory / ("ontologic-" + uuid.uuid4().hex + ".zip")
        state["report"] = extract(
            Rhino.RhinoDoc.ActiveDoc, selection, package, bool(AllowProxy),
            export_children=bool(globals().get("ExportChildren", True))
        )
        state["package"] = str(package)
        state["job"] = None
        state["ifc"] = None
        state["model"] = None
        state["status"] = "Exchange extracted; Start conversion explicitly."
    if any(events[name] for name in ("Start", "Poll", "Download", "Upload", "Cancel")):
        client = Client(str(BaseUrl), ApiKey, str(ProjectId))
        if events["Start"]:
            if not state["package"]:
                raise ValueError("Export explicit selection first.")
            job = client.start(
                state["package"], str(Filename), str(Revision), str(IdempotencyKey)
            )
            state["job"] = job["jobId"]
            state["status"] = job["state"]
        if events["Poll"]:
            if not state["job"]:
                raise ValueError("Start conversion first.")
            result = client.status(state["job"])
            state["status"] = result["state"]
            state["report"] = result
        if events["Download"]:
            result = client.result(state["job"])
            out = Path(str(OutputDirectory)).resolve() / (
                "ontologic-" + state["job"] + ".ifc"
            )
            client.transfer(result["download"]["url"], out, expected=result["result"])
            state["ifc"] = str(out)
            state["report"] = result["result"]
            state["status"] = "Validated IFC downloaded."
        if events["Upload"]:
            state["model"] = client.publish(state["job"])
            state["status"] = "Published new immutable revision."
        if events["Cancel"]:
            state["status"] = client.cancel(state["job"])["state"]
except Exception as error:
    # Never display urllib exceptions containing signed capabilities or API credentials.
    state["status"] = (
        str(error)
        if isinstance(error, ValueError)
        else type(error).__name__ + ": operation failed; check API/worker availability."
    )
JobId = state["job"]
Status = state["status"]
Report = json.dumps(state["report"], ensure_ascii=False)
PackagePath = state["package"]
IfcPath = state["ifc"]
Model = json.dumps(state["model"], ensure_ascii=False)
