# 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.
Set up materials.
'''
__version__ = '0.1'

import logging
import os
import random
import bpy

logger = logging.getLogger(__name__)


def assign_pbr_material(obj_names, textures_path):
    ''' Assign material with PBR textures pack. '''

    textures = sorted(os.listdir(textures_path))

    for obj_name in obj_names:

        part_name = obj_name.rpartition('_')[0]

        obj = bpy.data.objects[obj_name]
        if len(obj.material_slots) > 0:
            # should be only one material so clear all exist slots
            obj.data.materials.clear()

        if part_name in bpy.data.materials:
            # if material is already in scene
            obj.data.materials.append(bpy.data.materials[part_name])
            continue

        # create Principled BSDF based material
        bmat = bpy.data.materials.new(name=f'M_{part_name}')
        bmat.use_nodes = True
        principled_node = bmat.node_tree.nodes["Principled BSDF"]
        random_color = (
            round(random.uniform(0.1, 0.9), 3),
            round(random.uniform(0.1, 0.9), 3),
            round(random.uniform(0.1, 0.9), 3),
            1.0)
        bmat.diffuse_color = random_color
        principled_node.inputs['Base Color'].default_value = random_color

        for texture in textures:
            if not texture.startswith('T_' + part_name):
                continue
            if '_ao.' in texture:
                image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
                image_obj.colorspace_settings.name = 'Linear'
                texture_ao = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
                texture_ao.name = texture_ao.label = 'ambient_occlusion'
                texture_ao.location = -1000, 500
                texture_ao.image = bpy.data.images[image_obj.name]

                mix_node = bmat.node_tree.nodes.new(type="ShaderNodeMix")
                mix_node.location = -500, 500
                mix_node.data_type = 'RGBA'
                mix_node.blend_type = 'MULTIPLY'
                mix_node.inputs['Factor'].default_value = 0.5

                bmat.node_tree.links.new(texture_ao.outputs['Color'], mix_node.inputs[7])
                bmat.node_tree.links.new(mix_node.outputs[2], principled_node.inputs['Base Color'])


            if '_d.' in texture:
                image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
                image_obj.colorspace_settings.name = 'sRGB'
                texture_d = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
                texture_d.name = texture_d.label = 'diffuse'
                texture_d.location = -1000, 0
                texture_d.image = bpy.data.images[image_obj.name]

                if texture_ao:
                    bmat.node_tree.links.new(texture_d.outputs['Color'], mix_node.inputs[6])
                else:
                    bmat.node_tree.links.new(texture_d.outputs['Color'], principled_node.inputs['Base Color'])

            if '_m.' in texture:
                image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
                image_obj.colorspace_settings.name = 'Linear'
                texture_m = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
                texture_m.name = texture_m.label = 'metallic'
                texture_m.location = -1000, -500
                texture_m.image = bpy.data.images[image_obj.name]

                bmat.node_tree.links.new(texture_m.outputs['Color'], principled_node.inputs['Metallic'])

            if '_r.' in texture:
                image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
                image_obj.colorspace_settings.name = 'Linear'
                texture_r = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
                texture_r.name = texture_r.label = 'roughness'
                texture_r.location = -1000, -1000
                texture_r.image = bpy.data.images[image_obj.name]

                bmat.node_tree.links.new(texture_r.outputs['Color'], principled_node.inputs['Roughness'])

            if '_n.' in texture:
                image_obj = bpy.data.images.load(os.path.join(textures_path, texture))
                image_obj.colorspace_settings.name = 'Non-Color'
                texture_n = bmat.node_tree.nodes.new(type="ShaderNodeTexImage")
                texture_n.name = texture_n.label = 'normal'
                texture_n.location = -1000, -1500
                texture_n.image = bpy.data.images[image_obj.name]

                normal_node = bmat.node_tree.nodes.new(type="ShaderNodeNormalMap")
                normal_node.location = -500, -1500

                bmat.node_tree.links.new(texture_n.outputs['Color'], normal_node.inputs['Color'])
                bmat.node_tree.links.new(normal_node.outputs['Normal'], principled_node.inputs['Normal'])

        obj.data.materials.append(bmat)

    logger.info('Shading of %s objects is finished!', len(obj_names))
    return True
