# coding: utf-8
# Copyright (C) 2023 Ilia Kurochkin <brothermechanic@yandex.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
'''
DESCRIPTION.
- Build Blender scene from JSON data.
- Setup hierarchy.
- Setup materials.
- Setup LCS points.
- Apply Bledner scene transforms.
'''
__version__ = '0.2'

import collections
import logging
import random
import bpy
from blender.utils.object_transforms import apply_transforms
from blender.import_cad.import_hierarchy import (fc_placement,
                                                 hierarchy_list)
from blender.import_cad.import_materials import (assign_materials,
                                                 assign_black)

logger = logging.getLogger(__name__)

scene_scale = 0.001
blackbody_mat_name = 'Robossembler_Black_Body'


def json_to_blend(js_data):
    ''' Reads JSON data and creates Blender scene '''
    render_collection = bpy.data.collections.new('Render')
    bpy.context.scene.collection.children.link(render_collection)

    fc_file = list(js_data.keys())[0]

    imported_objects = collections.defaultdict(list)

    for js_obj in js_data[fc_file]:
        bobj = None

        if js_data[fc_file][js_obj]['type'] == 'LCS':
            if not js_data[fc_file][js_obj].get('Robossembler_SocketFlow'):
                # TODO test
                logger.info('LCS %s is not defined!', js_obj)
                continue
            bobj = bpy.data.objects.new(js_obj, None)
            bobj.empty_display_type = 'ARROWS'
            bobj.empty_display_size = round(random.uniform(0.05, 0.15), 3)
            bobj.show_in_front = True
            for attr in js_data[fc_file][js_obj].keys():
                if 'Robossembler' not in attr:
                    continue
                bobj[attr] = js_data[fc_file][js_obj][attr]
            render_collection.objects.link(bobj)
            imported_objects['objs_lcs'].append(bobj.name)

        elif js_data[fc_file][js_obj]['type'] == 'PART':
            if js_data[fc_file][js_obj].get('mesh'):
                verts = js_data[fc_file][js_obj]['mesh'][0]
                edges = []
                faces = js_data[fc_file][js_obj]['mesh'][1]

                # create blender object data
                bmesh = bpy.data.meshes.new(name=js_obj)
                bmesh.from_pydata(verts, edges, faces)
                bmesh.update()
                bobj = bpy.data.objects.new(js_obj, bmesh)
                render_collection.objects.link(bobj)

        if bobj:
            fc_placement(bobj,
                         js_data[fc_file][js_obj]['fc_location'],
                         js_data[fc_file][js_obj]['fc_rotation'],
                         scene_scale)
            if bobj.type == 'MESH':
                bobj.scale = (scene_scale, scene_scale, scene_scale)
                apply_transforms(bobj, scale=True)

            # construct assembly hierarchy
            hierarchy_objs = hierarchy_list(
                bobj, js_data[fc_file][js_obj]['hierarchy'], scene_scale)
            for hierarchy_obj in hierarchy_objs:
                render_collection.objects.link(hierarchy_obj)
                imported_objects['objs_hierarchy'].append(hierarchy_obj.name)

            # one material for the whole object
            if bobj.type == 'MESH':
                if js_data[fc_file][js_obj].get('material'):
                    fem_mat = js_data[fc_file][js_obj]['material']
                    assign_materials(bobj, fem_mat)
                    imported_objects['objs_foreground'].append(bobj.name)
                else:
                    assign_black(bobj)
                    imported_objects['objs_background'].append(bobj.name)

    logger.info('Generated %s objects without errors',
                len(sum(list(imported_objects.values()), [])))
    return imported_objects
