# GO3D Revit handoff R01. Run inside licensed Revit with pyRevit.
# Uses Autodesk's IFC importer. Not an authoring/LOD acceptance tool.
from __future__ import print_function
import os
import json
import hashlib
import datetime


def file_hash(path):
    digest = hashlib.sha256()
    with open(path, 'rb') as stream:
        while True:
            chunk = stream.read(1048576)
            if not chunk:
                break
            digest.update(chunk)
    return digest.hexdigest()


def convert(application, source, target, options_class, inspect_document):
    if not os.path.isfile(source) or not source.lower().endswith('.ifc'):
        raise ValueError('Choose an existing IFC file.')
    if not target.lower().endswith('.rvt'):
        raise ValueError('Choose a new .rvt output path.')
    receipt = target + '.go3d.json'
    if os.path.exists(target) or os.path.exists(receipt):
        raise ValueError('Choose a new filename. Existing files will not be overwritten.')
    record = {'schema': 'go3d.revit-conversion.v1',
              'sourceFile': os.path.basename(source), 'sourceSHA256': file_hash(source),
              'createdUTC': datetime.datetime.utcnow().isoformat() + 'Z',
              'revitVersion': str(application.VersionNumber),
              'method': 'Revit OpenIFCDocument then SaveAs; reopened for readability',
              'acceptance': 'Pending independent geometry, units, category and scope review',
              'nativeParametricAuthoringVerified': False, 'acceptedLOD250Regions': 0}
    document = None
    try:
        document = application.OpenIFCDocument(source)
        record['imported'] = inspect_document(document)
        options = options_class()
        options.OverwriteExistingFile = False
        document.SaveAs(target, options)
    finally:
        if document is not None:
            document.Close(False)
    if not os.path.isfile(target) or os.path.getsize(target) == 0:
        raise ValueError('Revit did not produce a nonempty RVT. Inspect its import messages.')
    document = None
    try:
        document = application.OpenDocumentFile(target)
        record['reopened'] = inspect_document(document)
    finally:
        if document is not None:
            document.Close(False)
    record['outputSHA256'] = file_hash(target)
    record['status'] = 'Saved and reopened in Revit; BIM content acceptance still pending'
    with open(receipt, 'w') as stream:
        json.dump(record, stream, indent=2)
    return record


def main():
    from pyrevit import forms
    from Autodesk.Revit.DB import SaveAsOptions, FilteredElementCollector
    source = forms.pick_file(file_ext='ifc', title='Choose the GO3D IFC study')
    if not source:
        return
    target = forms.save_file(file_ext='rvt', default_name='GO3D_Jambo_Study.rvt', title='Save a new Revit study')
    if not target:
        return

    def inspect_document(document):
        return {'nonTypeElementCount': FilteredElementCollector(document).WhereElementIsNotElementType().GetElementCount(),
                'warningCount': document.GetWarnings().Count}
    try:
        convert(__revit__.Application, source, target, SaveAsOptions, inspect_document)
        forms.alert('RVT saved and reopened. A source/validation receipt is beside it. Review geometry, units, categories and warnings before accepting BIM scope.', title='GO3D conversion complete')
    except Exception as error:
        forms.alert('Conversion or reopen check did not finish: ' + str(error) + '\nNo BIM acceptance was granted. Inspect Revit messages and any output file before retrying with a new name.', title='GO3D conversion needs review')


if __name__ == '__main__':
    main()
