# Copyright (C) 2022 Thomas Hoppe (h0bB1T). All rights reserved.
#
# Unauthorized copying of this file via any medium is strictly prohibited.
# Proprietary and confidential.

import bpy

from bpy.types import Operator, UILayout
from bpy.props import FloatVectorProperty

from ..utils.ui import insert_pbr_channels

from ..properties import GrungeMappingProperties, MappingProperties, PBRMappingProperties, ImageMappingProperties, Properties
from ..preferences import PreferencesPanel

from ..snw.ui import insert_category_and_preview
from ..snw.node_info import node_info

from ..operators.helpers.load_node_info import load_node_info
from ..registries.texture_registry import RepositoryType, TextureRegistry


class UI_OT_edit_node(Operator):
    """
    Edit dialogs for PBR, grunge and vertex colors, shown when hitting 'E' with supported node as active node.
    """
    bl_idname = 'snw.edit_node'
    bl_label = 'SNW Edit Node'
    bl_description = 'Edit group texture settings'
    bl_options = {'REGISTER'}


    custom_color: FloatVectorProperty(subtype='COLOR') # type: ignore


    def __draw_common_settings(self, l: UILayout, props: MappingProperties, skip_bevel: bool = False):
        # Mapping and interpolation.
        l.separator()
        l.label(text='Mapping', icon='MOD_UVPROJECT')
        l.row(align=True).prop(props, 'mapping', expand=True)
        if props.mapping in { 'LBOX', 'GENBOX', 'GBOX' }:
            l.prop(props, 'blend', slider=True)

        l.separator()
        l.label(text='Anti Repeat', icon='ALIGN_FLUSH')
        l.row(align=True).prop(props, 'anti_repeat_style', expand=True)
        if props.anti_repeat_style != 'OFF':
            rc = l.column(align=True)
            #rc.use_property_split = True
            rc.prop(props, 'anti_repeat_scale', slider=True)
            rc.prop(props, 'anti_repeat_distortion', slider=True)
            rc.prop(props, 'anti_repeat_style_param_0', slider=True, text='Distortion Scale' if props.anti_repeat_style == 'VORONOI' else 'Levels')
            rc.prop(props, 'anti_repeat_seed', slider=True)

        l.separator()
        l.label(text='Interpolation', icon='IPO_BEZIER')
        l.row(align=True).prop(props, 'interpolation', expand=True)

        if not skip_bevel:
            l.separator()
            l.row(align=True).prop(props, 'bevel_samples', slider=True)


    def __draw_pbr_edit(
        self, 
        layout: UILayout, 
        tree_name: str = '', 
        edit_index: int = 0, 
        tag: str = ''
        ):
        c = layout
        if TextureRegistry.instance().get_category_enums(RepositoryType.PBR):
            props = Properties.get().pbr_edit(edit_index) # type: PBRMappingProperties

            insert_category_and_preview(
                c, 
                PreferencesPanel.get().preview_scale_side, 
                PreferencesPanel.get().preview_scale_side_popup,
                props
            )

            texture_entry = props.texture_entry()
            if texture_entry:
                insert_pbr_channels(c.row(align=True), texture_entry)
                if len(props.get_variants()) > 1:
                    c.row(align=True).prop(props, 'variants', expand=True)

            self.__draw_common_settings(c, props)   

            c.separator()
            c.prop(props, 'invert_normal', icon='RNDCURVE', expand=True)
            c.separator()
            c.label(text='Depth Mode', icon='MOD_DISPLACE')
            if texture_entry.info.pbr.displace:
                pr = c.row(align=True)
                pr.prop(props, 'depth_mode', text='')
                if props.depth_mode == 'POM':
                    pr = c.row(align=True).split(factor=0.4, align=True)
                    pr.label(text='Levels:')
                    pr.row(align=True).prop(props, 'pom_levels', expand=True)
                    pr = c.row(align=True).split(factor=0.4, align=True)
                    pr.label(text='Sub-Levels:')
                    pr.row(align=True).prop(props, 'pom_fine_levels', expand=True)

                if props.depth_mode in { 'PARALLAX', 'POM' }:
                    c.label(text='Warning: Parallax Mapping is highly experimental!', icon='ERROR')
                    c.label(text='Works in UV mode only (yet) and does not support silhouettes')
            else:
                c.label(text='No displacement map', icon='ERROR')
        else:
            c.label(text='No PBR categories found')


    def __draw_grunge_edit(
        self,
        layout: UILayout,
        tree_name: str = '', 
        edit_index: int = 0, 
        tag: str = ''
        ):
        c = layout
        if TextureRegistry.instance().get_category_enums(RepositoryType.Gray):
            props = Properties.get().grunge_edit(edit_index) # type: GrungeMappingProperties

            insert_category_and_preview(
                c, 
                PreferencesPanel.get().preview_scale_side, 
                PreferencesPanel.get().preview_scale_side_popup,
                props
            )
            #texture_entry = props.texture_entry()

            self.__draw_common_settings(c, props)   
        else:
            c.label(text='No Grunge categories found')


    def __draw_image_edit(
        self,
        layout: UILayout,
        tree_name: str = '', 
        edit_index: int = 0, 
        tag: str = ''
        ):
        c = layout
        if TextureRegistry.instance().get_category_enums(RepositoryType.Image):
            props = Properties.get().image_edit(edit_index) # type: ImageMappingProperties

            insert_category_and_preview(
                c, 
                PreferencesPanel.get().preview_scale_side, 
                PreferencesPanel.get().preview_scale_side_popup,
                props
            )
            #texture_entry = props.texture_entry()

            self.__draw_common_settings(c, props, skip_bevel=True)   
        else:
            c.label(text='No Image categories found')


    def execute(self, context: bpy.types.Context):
        return{'FINISHED'}


    def __toggle_paint(self, context: bpy.types.Context, node: bpy.types.ShaderNodeGroup):
        # Find the image texture and UV Map.
        obj = context.active_object
        data = obj.data # type: bpy.types.Mesh
        tree = node.node_tree
        image, uv_map = None, None
        for n in tree.nodes:
            if n.bl_idname == 'ShaderNodeTexImage' and n.image:
                image = n.image
            elif n.bl_idname == 'ShaderNodeUVMap':
                uv_map = n.uv_map

            if image and uv_map:
                # We have all infos.
                break

        if image and uv_map:
            bpy.ops.snw.support_paint_command(mode='SET_IMAGE', image=image.name, uv_map=uv_map)


    def invoke(self, context, event):
        node = context.active_node
        if node:
            ni = node_info(node)
            if len(ni) == 1 and ni[0].type == 'I':
                """
                If this is one of our image nodes, switch to paint with this texture.
                """
                self.__toggle_paint(context, node)
            elif node.bl_idname == 'ShaderNodeVertexColor':
                props = Properties.get()
                props.vertex_color_set = node.layer_name
                bpy.ops.object.mode_set(mode='EDIT')
            elif node.bl_idname == 'ShaderNodeGroup':
                """
                Load details from PBR and grunge nodes and store them into properties
                for use in draw() below.
                """
                infos = [ i for i in ni if i.type in ['P', 'G', 'T'] ]
                if len(infos) > 0:
                    pbr_index, grunge_index, image_index = 0, 0, 0
                    for inf in infos:
                        if inf.type == 'P':
                            load_node_info(inf.tree.name, inf.type, pbr_index, inf.tag)
                            pbr_index += 1
                        elif inf.type == 'T':
                            load_node_info(inf.tree.name, inf.type, image_index, inf.tag)
                            image_index += 1
                        elif inf.type == 'G':
                            load_node_info(inf.tree.name, inf.type, grunge_index, inf.tag)
                            grunge_index += 1        
                return context.window_manager.invoke_props_dialog(self)

        # No UI needed.
        return{'FINISHED'}


    def draw(self, context):
        if context.active_node.bl_idname == 'ShaderNodeGroup':
            infos = [ i for i in node_info(context.active_node) if i.type in ['P', 'G', 'T'] ]
            if len(infos) > 0:
                self.layout.ui_units_x = 16 * len(infos)
                r = self.layout.grid_flow(columns=len(infos))
                pbr_index, grunge_index, image_index = 0, 0, 0
                for inf in infos:
                    if inf.type == 'P':
                        self.__draw_pbr_edit(r.box().column(align=True), inf.tree.name, pbr_index, inf.tag)
                        pbr_index += 1
                    elif inf.type == 'T':
                        self.__draw_image_edit(r.box().column(align=True), inf.tree.name, image_index, inf.tag)
                        image_index += 1
                    elif inf.type == 'G':
                        self.__draw_grunge_edit(r.box().column(align=True), inf.tree.name, grunge_index, inf.tag)
                        grunge_index += 1
            else:
                self.layout.label(text='Nothing to edit')
        else:
            self.layout.label(text='Nothing to edit')
