# 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, json

from typing import Any, Dict, List

from ..utils.io import decode_json

 
class NodeInfo:
    """
    Returned from node_info, used to create the UI for loading information and editing the node.
    """
    def __init__(self, tree: bpy.types.NodeTree, name: str, tag: str, type: str):
        self.tree = tree
        self.name = name
        self.tag = tag
        self.type = type


def node_info(n: bpy.types.NodeGroup, recursive: bool = True) -> List[NodeInfo]:
    """
    Find (1 level iterative) all editable PBR and Grunge infos.
    """
    r = []

    if n and n.bl_idname == 'ShaderNodeGroup':
        tree = n.node_tree
        nfo = tree.snw_node_info # type: str
        try:
            info = decode_json(nfo)
            if info.get('type', '') != '':
                r.append(NodeInfo(tree, info.get('name', ''), nfo, info.get('type', '')))
            else:
                if recursive:
                    for s in tree.nodes:
                        r.extend(node_info(s, False)) # Limit to 1 level.
        except: # No Error
            if nfo.startswith('Grunge'):
                r.append(NodeInfo(tree, n.name, '', 'G'))
            elif nfo.startswith('PBR'):
                r.append(NodeInfo(tree, n.name, '', 'P'))
            elif nfo.startswith('Image'):
                r.append(NodeInfo(tree, n.name, '', 'T'))

    return r


def encode_pbr_info(
    name: str, 
    category: str, 
    pbr: str, 
    variant: int, 
    bin_hash: str, 
    mapping: str, 
    blend: float,
    interpolation: str,
    anti_repeat_style: str,
    anti_repeat_scale: float,
    anti_repeat_distortion: float,
    anti_repeat_style_param_0: float,
    anti_repeat_seed: float,
    depth_mode: str,
    pom_levels: str,
    pom_fine_levels: str,
    bevel_samples: int,
    invert_normal: bool,
    ) -> str:
    return json.dumps({
        'type': 'P',
        'name': name,
        'category': category,
        'pbr': pbr,
        'variant': variant,
        'bin_hash': bin_hash,
        'mapping': mapping,
        'blend': blend,
        'interpolation': interpolation,
        'anti_repeat_style': anti_repeat_style,
        'anti_repeat_scale': anti_repeat_scale,
        'anti_repeat_distortion': anti_repeat_distortion,
        'anti_repeat_style_param_0': anti_repeat_style_param_0,
        'anti_repeat_seed': anti_repeat_seed,
        'depth_mode': depth_mode,
        'pom_levels': pom_levels,
        'pom_fine_levels': pom_fine_levels,
        'bevel_samples': bevel_samples,
        'invert_normal': invert_normal,
    })


def encode_image_info(
    name: str, 
    category: str, 
    image: str, 
    bin_hash: str, 
    mapping: str, 
    blend: float,
    interpolation: str,
    anti_repeat_style: str,
    anti_repeat_scale: float,
    anti_repeat_distortion: float,
    anti_repeat_style_param_0: float,
    anti_repeat_seed: float
    ) -> str:
    return json.dumps({
        'type': 'T',
        'name': name,
        'category': category,
        'image': image,
        'bin_hash': bin_hash,
        'mapping': mapping,
        'blend': blend,
        'interpolation': interpolation,
        'anti_repeat_style': anti_repeat_style,
        'anti_repeat_scale': anti_repeat_scale,
        'anti_repeat_distortion': anti_repeat_distortion,
        'anti_repeat_style_param_0': anti_repeat_style_param_0,
        'anti_repeat_seed': anti_repeat_seed
    })


def encode_grunge_info(
    name: str, 
    category: str, 
    grunge: str, 
    bin_hash: str, 
    mapping: str, 
    blend: float,
    interpolation: str,
    anti_repeat_style: str,
    anti_repeat_scale: float,
    anti_repeat_distortion: float,
    anti_repeat_style_param_0: float,
    anti_repeat_seed: float,
    bevel_samples: int
    ) -> str:
    return json.dumps({
        'type': 'G',
        'name': name,
        'category': category,
        'grunge': grunge,
        'bin_hash': bin_hash,
        'mapping': mapping,
        'blend': blend,
        'interpolation': interpolation,
        'anti_repeat_style': anti_repeat_style,
        'anti_repeat_scale': anti_repeat_scale,
        'anti_repeat_distortion': anti_repeat_distortion,
        'anti_repeat_style_param_0': anti_repeat_style_param_0,
        'anti_repeat_seed': anti_repeat_seed,
        'bevel_samples': bevel_samples,
    })


def update_blend_value(info: str, blend: float) -> str:
    d = json.loads(info)
    d['blend'] = blend
    return json.dumps(d)


def update_anti_repeat_value(
    info: str, 
    anti_repeat_scale: float,
    anti_repeat_distortion: float,
    anti_repeat_style_param_0: float,
    anti_repeat_seed: float
    ) -> str:
    d = json.loads(info)
    d['anti_repeat_scale'] = anti_repeat_scale
    d['anti_repeat_distortion'] = anti_repeat_distortion
    d['anti_repeat_style_param_0'] = anti_repeat_style_param_0
    d['anti_repeat_seed'] = anti_repeat_seed
    return json.dumps(d)    


def encode_image_paint_info(name: str, sub_type: str) -> str:
    return json.dumps({
        'type': 'I',
        'name': name,
        'sub_type': sub_type
    })


def encode_pbr_map_info(pbr_map_dict: Dict[str, Any]) -> str:
    return json.dumps({
        'type': 'M',
        'map': pbr_map_dict
    })
