import gc
import os
import bpy
import uuid
import shutil

from simplygon import simplygon_loader
from simplygon import Simplygon

class Simplygon_Process():
  def export_scene(self, export_dir):
    export_scene_file_path = os.path.join(export_dir, 'export.glb')
    (major_version, minor_version, _) = bpy.app.version
    # export_materials changed from boolean to enum in 2.91
    export_materials_value = True
    if (major_version == 2 and minor_version > 90) or major_version >= 3:
      export_materials_value = 'EXPORT'
    bpy.ops.export_scene.gltf(export_format = 'GLB', \
                              use_selection = True, \
                              filepath = export_scene_file_path,
                              export_image_format = 'AUTO', \
                              export_texcoords  = True, \
                              export_normals   = True, \
                              export_draco_mesh_compression_enable = False, \
                              export_tangents = True, \
                              export_materials  = export_materials_value, \
                              export_colors = True, \
                              export_cameras = True, \
                              export_yup = True, \
                              export_def_bones = False, \
                              export_current_frame = False, \
                              export_skins = True)
    return export_scene_file_path

  def import_scene(self, sg, import_dir, pipeline):
    if not pipeline.GetPipelineSettings().GetIntermediateStep():
      import_lod_dir = os.path.join(import_dir, 'LOD{}'.format(self.lod_index))
      os.makedirs(import_lod_dir)
      import_scene_file_path = os.path.join(import_lod_dir, 'import.glb')

      if pipeline.GetProcessedScene():
        scene_exporter = sg.CreateSceneExporter()
        scene_exporter.SetScene(pipeline.GetProcessedScene())
        scene_exporter.SetExportFilePath( import_scene_file_path )
        scene_exporter.RunExport()

        current_objects = set(bpy.context.scene.objects)
        bpy.ops.import_scene.gltf(filepath = import_scene_file_path)
        imported_objects = set(bpy.context.scene.objects) - current_objects
        for node in  imported_objects:
          node.name = node.name + '_LOD{}'.format(self.lod_index)
          if node.data:
            node.data.name = node.data.name + '_LOD{}'.format(self.lod_index)

      self.lod_index = self.lod_index + 1

    for i in range(pipeline.GetCascadedPipelineCount()):
      self.import_scene(sg, import_dir, pipeline.GetCascadedPipelineByIndex(i))

  def run_simplygon(self, sg, temp_dir):
    import_dir = os.path.join(temp_dir, 'import')
    export_dir = os.path.join(temp_dir, 'export')
    os.makedirs(import_dir)
    os.makedirs(export_dir)

    export_scene_file_path = self.export_scene(export_dir)

    pipeline = sg.CreateAggregationPipeline()
    
    pipeline_AggregationSettings = pipeline.GetAggregationSettings()
    pipeline_AggregationSettings.SetMergeGeometries(True)
    
    pipeline_MappingImageSettings = pipeline.GetMappingImageSettings()
    pipeline_MappingImageSettings.SetGenerateMappingImage(True)
    pipeline_MappingImageSettings.SetApplyNewMaterialIds(True)
    pipeline_MappingImageSettings.SetGenerateTexCoords(True)
    
    baseColor_MaterialCaster = pipeline.AddMaterialCasterByType('Color', 0)
    baseColor_MaterialCasterSettings = baseColor_MaterialCaster.GetMaterialCasterSettings()
    baseColor_MaterialCasterSettings.SetMaterialChannel('Basecolor')
    
    pipeline.RunSceneFromFile(export_scene_file_path, None, Simplygon.EPipelineRunMode_RunInThisProcess)

    self.lod_index = 1
    self.import_scene(sg, import_dir, pipeline)

  def run(self):
    if len([m for m in bpy.context.selected_objects if m.type == 'MESH']) == 0:
      raise Exception('Please select a mesh to process!')
    SIMPLYGON_TEMP = os.getenv('SIMPLYGON_9_TEMP')
    if not SIMPLYGON_TEMP:
      raise Exception('Simplygon initialization error: SIMPLYGON_9_TEMP not set')
    else:
      SIMPLYGON_TEMP = os.path.expandvars(SIMPLYGON_TEMP)
    temp_dir = os.path.join(SIMPLYGON_TEMP, str(uuid.uuid4()))
    os.makedirs(temp_dir)

    sg = simplygon_loader.init_simplygon()
    if sg is None:
      raise Exception(Simplygon.GetLastInitializationError())

    self.run_simplygon(sg, temp_dir)

    sg = None
    gc.collect()
    return {'FINISHED'}


if __name__ == "__main__":

    simplygon_process = Simplygon_Process()
    simplygon_process.run()
