# -*- coding:utf-8 -*-

# ##### BEGIN GPL LICENSE BLOCK #####
#
#  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 2
#  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.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110- 1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# <pep8 compliant>

# ----------------------------------------------------------
# Author: Stephen Leger (s-leger)
# Inspired by Asset-Flinguer
# ----------------------------------------------------------
import sys
from mathutils import Vector
import bpy


def log(s):
    print("[log]" + s)


def create_lamp(context, loc):
    bpy.ops.object.light_add(
        type='POINT',
        radius=1,
        align='WORLD',
        location=loc)
    lamp = context.active_object
    lamp.data.use_nodes = True
    lamp.location = loc
    tree = lamp.data.node_tree
    return tree, tree.nodes, lamp.data


def create_camera(context, loc, rot):
    bpy.ops.object.camera_add(
        align='WORLD',
        enter_editmode=False,
        location=loc,
        rotation=rot)
    cam = context.active_object
    cam.location = loc
    cam.rotation_euler = rot
    context.scene.camera = cam
    return cam


def get_center(o):
    x, y, z = o.bound_box[0]
    min_x = x
    min_y = y
    min_z = z
    x, y, z = o.bound_box[6]
    max_x = x
    max_y = y
    max_z = z
    return Vector((
        min_x + 0.5 * (max_x - min_x),
        min_y + 0.5 * (max_y - min_y),
        min_z + 0.5 * (max_z - min_z)))


def apply_simple_material(o, name, color):
    m = bpy.data.materials.new(name)
    m.use_nodes = True
    for node in m.node_tree.nodes:
        if node.bl_idname == "ShaderNodeBsdfPrincipled":
            node.inputs[0].default_value = color
            break
    o.data.materials.append(m)


def generateThumb(context, cls, preset, engine):
    log("### RENDER THUMB ############################")

    # Cleanup scene
    for o in context.scene.objects:
        o.select_set(state=True)

    bpy.ops.object.delete()

    log("Start generating: %s" % cls)

    # setup render

    context.scene.render.engine = engine

    if engine == 'CYCLES':
        cycles = context.scene.cycles
        cycles.progressive = 'PATH'
        cycles.samples = 24
        try:
            cycles.use_square_samples = True
        except:
            pass
        cycles.preview_samples = 24
        cycles.aa_samples = 24
        cycles.transparent_max_bounces = 8
        cycles.transparent_min_bounces = 8
        cycles.transmission_bounces = 8
        cycles.max_bounces = 8
        cycles.min_bounces = 6
        cycles.caustics_refractive = False
        cycles.caustics_reflective = False
        cycles.use_transparent_shadows = True
        cycles.diffuse_bounces = 1
        cycles.glossy_bounces = 4

    elif engine == 'BLENDER_EEVEE':
        eevee = context.scene.eevee
        eevee.use_gtao = True
        eevee.use_ssr = True
        eevee.use_soft_shadows = True
        eevee.taa_render_samples = 64
    else:
        raise RuntimeError("Unsupported render engine %s" % engine)

    render = context.scene.render

    # engine settings
    render.resolution_x = 150
    render.resolution_y = 100
    render.filepath = preset[:-3] + ".png"

    # create object, loading preset
    getattr(bpy.ops.archipack, cls)('INVOKE_DEFAULT', filepath=preset, auto_manipulate=False)
    o = context.active_object
    size = o.dimensions
    center = get_center(o)

    # opposite / tan (0.5 * fov)  where fov is 49.134 deg
    dist = max(size) / 0.32
    loc = center + dist * Vector((-0.5, -1, 0.5)).normalized()

    log("Prepare camera")
    cam = create_camera(context, loc, (1.150952, 0.0, -0.462509))
    cam.data.lens = 50

    for ob in context.scene.objects:
        ob.select_set(state=False)

    o.select_set(state=True)

    bpy.ops.view3d.camera_to_view_selected()
    cam.data.lens = 45

    log("Prepare scene")
    # add plane
    bpy.ops.mesh.primitive_plane_add(
        size=1000,
        align='WORLD',
        enter_editmode=False,
        location=(0, 0, 0)
    )

    p = context.active_object
    apply_simple_material(p, "Plane", (1, 1, 1, 1))

    # add 3 lights
    tree, nodes, lamp = create_lamp(context, (3.69736, -7, 6.0))
    lamp.energy = 1000
    emit = nodes["Emission"]
    emit.inputs[1].default_value = 2000.0

    tree, nodes, lamp = create_lamp(context, (9.414563179016113, 5.446230888366699, 5.903861999511719))
    lamp.energy = 400
    emit = nodes["Emission"]
    falloff = nodes.new(type="ShaderNodeLightFalloff")
    falloff.inputs[0].default_value = 5
    tree.links.new(falloff.outputs[2], emit.inputs[1])

    tree, nodes, lamp = create_lamp(context, (-7.847615718841553, 1.03135085105896, 5.903861999511719))
    lamp.energy = 200
    emit = nodes["Emission"]
    falloff = nodes.new(type="ShaderNodeLightFalloff")
    falloff.inputs[0].default_value = 5
    tree.links.new(falloff.outputs[2], emit.inputs[1])

    # Set output filename.
    render.use_file_extension = True
    render.use_overwrite = True
    render.use_compositing = False
    render.use_sequencer = False
    render.resolution_percentage = 100
    # render.image_settings.file_format = 'PNG'
    # render.image_settings.color_mode = 'RGBA'
    # render.image_settings.color_depth = '8'

    # Configure output size.
    log("Render")

    # Render thumbnail
    bpy.ops.render.render(write_still=True)

    log("### COMPLETED ############################")


if __name__ == "__main__":

    preset = ""
    engine = 'BLENDER_EEVEE' #'CYCLES'
    for arg in sys.argv:
        if arg.startswith("cls:"):
            cls = arg[4:]
        if arg.startswith("preset:"):
            preset = arg[7:]
        if arg.startswith("matlib:"):
            matlib = arg[7:]
        if arg.startswith("addon:"):
            module = arg[6:]
        if arg.startswith("engine:"):
            engine = arg[7:]
    try:
        # log("### ENABLE %s ADDON ############################" % module)
        bpy.ops.preferences.addon_enable(module=module)
        # log("### MATLIB PATH ############################")
        bpy.context.preferences.addons[module].preferences.matlib_path = matlib
    except:
        raise RuntimeError("module name not found")
    # log("### GENERATE ############################")
    generateThumb(bpy.context, cls, preset, engine)
