import json

import FreeCAD as App
import Part
import Sketcher


FREECAD_COMMIT = "0108fd4b4850cc46e625b60e53cea7a7bbe69f8d"
TYPE_IDS = [
    "PartDesign::Pad",
    "PartDesign::Pocket",
    "PartDesign::Revolution",
    "PartDesign::Groove",
    "PartDesign::AdditiveLoft",
    "PartDesign::SubtractiveLoft",
    "PartDesign::AdditivePipe",
    "PartDesign::SubtractivePipe",
    "PartDesign::Fillet",
    "PartDesign::Chamfer",
    "PartDesign::Draft",
    "PartDesign::Thickness",
    "PartDesign::Mirrored",
    "PartDesign::MultiTransform",
    "PartDesign::LinearPattern",
    "PartDesign::PolarPattern",
    "PartDesign::Hole",
]
ACCEPTED_EMPTY_TYPE_IDS = {
    "PartDesign::Mirrored",
    "PartDesign::MultiTransform",
    "PartDesign::LinearPattern",
    "PartDesign::PolarPattern",
}


def run_case(type_id):
    case_id = "missing-input-" + type_id.split("::", 1)[1].lower()
    document = App.newDocument("FailureOracle_" + case_id.replace("-", "_"))
    try:
        body = document.addObject("PartDesign::Body", "Body")
        feature = document.addObject(type_id, "Feature")
        body.addObject(feature)
        recompute_result = document.recompute()
        shape_null = bool(feature.Shape.isNull())
        state = [str(value) for value in feature.State]
        try:
            status_string = str(feature.getStatusString())
        except Exception:
            status_string = ""
        invalid = shape_null and ("Invalid" in state or status_string != "Valid")
        observed = "rejected" if invalid else "accepted-empty" if shape_null else "accepted"
        expected = "accepted-empty" if type_id in ACCEPTED_EMPTY_TYPE_IDS else "rejected"
        return {
            "id": case_id,
            "typeId": type_id,
            "inputClass": "missing-required-input",
            "expected": expected,
            "observed": observed,
            "passed": observed == expected,
            "recomputeResult": bool(recompute_result),
            "shapeNull": shape_null,
            "state": state,
            "statusString": status_string,
        }
    except Exception as error:
        expected = "accepted-empty" if type_id in ACCEPTED_EMPTY_TYPE_IDS else "rejected"
        return {
            "id": case_id,
            "typeId": type_id,
            "inputClass": "missing-required-input",
            "expected": expected,
            "observed": "rejected",
            "passed": expected == "rejected",
            "errorType": type(error).__name__,
            "error": str(error),
        }
    finally:
        App.closeDocument(document.Name)


cases = [run_case(type_id) for type_id in TYPE_IDS]
report = {
    "schemaVersion": 1,
    "baselineId": "freecad-1.1.1-partdesign-failure-oracle",
    "freecadVersion": ".".join(App.Version()[0:3]),
    "gitCommit": FREECAD_COMMIT,
    "status": "pass" if all(case["passed"] for case in cases) else "failed",
    "summary": {
        "cases": len(cases),
        "passed": sum(1 for case in cases if case["passed"]),
        "rejected": sum(1 for case in cases if case["observed"] == "rejected"),
        "acceptedEmpty": sum(1 for case in cases if case["observed"] == "accepted-empty"),
        "accepted": sum(1 for case in cases if case["observed"] == "accepted"),
    },
    "cases": cases,
}
print("FREECAD_PARTDESIGN_FAILURE_ORACLE_RESULT=" + json.dumps(report, sort_keys=True))
