from avalon.maya import lib
from avalon import api

import maya.cmds as cmds


class VRayProxyLoader(api.Loader):
    """Load VRayMesh proxy"""

    families = ["colorbleed.vrayproxy"]
    representations = ["vrmesh"]

    label = "Import VRay Proxy"
    order = -10
    icon = "code-fork"
    color = "orange"

    def load(self, context, name, namespace, data):

        from avalon.maya.pipeline import containerise
        from colorbleed.maya.lib import namespaced

        asset_name = context['asset']["name"]
        namespace = namespace or lib.unique_namespace(
            asset_name + "_",
            prefix="_" if asset_name[0].isdigit() else "",
            suffix="_",
        )

        # Ensure V-Ray for Maya is loaded.
        cmds.loadPlugin("vrayformaya", quiet=True)

        with lib.maintained_selection():
            cmds.namespace(addNamespace=namespace)
            with namespaced(namespace, new=False):
                nodes = self.create_vray_proxy(name,
                                               filename=self.fname)

        self[:] = nodes
        if not nodes:
            return

        return containerise(
            name=name,
            namespace=namespace,
            nodes=nodes,
            context=context,
            loader=self.__class__.__name__)

    def update(self, container, representation):

        node = container['objectName']
        assert cmds.objExists(node), "Missing container"

        members = cmds.sets(node, query=True) or []
        vraymeshes = cmds.ls(members, type="VRayMesh")
        assert vraymeshes, "Cannot find VRayMesh in container"

        filename = api.get_representation_path(representation)

        for vray_mesh in vraymeshes:
            cmds.setAttr("{}.fileName".format(vray_mesh),
                         filename,
                         type="string")

        # Update metadata
        cmds.setAttr("{}.representation".format(node),
                     str(representation["_id"]),
                     type="string")

    def remove(self, container):

        # Delete container and its contents
        if cmds.objExists(container['objectName']):
            members = cmds.sets(container['objectName'], query=True) or []
            cmds.delete([container['objectName']] + members)

        # Remove the namespace, if empty
        namespace = container['namespace']
        if cmds.namespace(exists=namespace):
            members = cmds.namespaceInfo(namespace, listNamespace=True)
            if not members:
                cmds.namespace(removeNamespace=namespace)
            else:
                self.log.warning("Namespace not deleted because it "
                                 "still has members: %s", namespace)

    def switch(self, container, representation):
        self.update(container, representation)

    def create_vray_proxy(self, name, filename):
        """Re-create the structure created by VRay to support vrmeshes

        Args:
            name(str): name of the asset

        Returns:
            nodes(list)
        """

        # Create nodes
        vray_mesh = cmds.createNode('VRayMesh', name="{}_VRMS".format(name))
        mesh_shape = cmds.createNode("mesh", name="{}_GEOShape".format(name))
        vray_mat = cmds.shadingNode("VRayMeshMaterial", asShader=True, 
                                   name="{}_VRMM".format(name))
        vray_mat_sg = cmds.sets(name="{}_VRSG".format(name),
                                empty=True,
                                renderable=True,
                                noSurfaceShader=True)

        cmds.setAttr("{}.fileName".format(vray_mesh),
                     filename,
                     type="string")

        # Create important connections
        cmds.connectAttr("time1.outTime",
                         "{0}.currentFrame".format(vray_mesh))
        cmds.connectAttr("{}.fileName2".format(vray_mesh),
                         "{}.fileName".format(vray_mat))
        cmds.connectAttr("{}.instancing".format(vray_mesh),
                         "{}.instancing".format(vray_mat))
        cmds.connectAttr("{}.output".format(vray_mesh),
                         "{}.inMesh".format(mesh_shape))
        cmds.connectAttr("{}.overrideFileName".format(vray_mesh),
                         "{}.overrideFileName".format(vray_mat))
        cmds.connectAttr("{}.currentFrame".format(vray_mesh),
                         "{}.currentFrame".format(vray_mat))

        # Set surface shader input
        cmds.connectAttr("{}.outColor".format(vray_mat),
                         "{}.surfaceShader".format(vray_mat_sg))

        # Connect mesh to shader
        cmds.sets([mesh_shape], addElement=vray_mat_sg)

        group_node = cmds.group(empty=True, name="{}_GRP".format(name))
        mesh_transform = cmds.listRelatives(mesh_shape,
                                            parent=True, fullPath=True)
        cmds.parent(mesh_transform, group_node)
        nodes = [vray_mesh, mesh_shape, vray_mat, vray_mat_sg, group_node]

        # Fix: Force refresh so the mesh shows correctly after creation
        cmds.refresh()
        cmds.setAttr("{}.geomType".format(vray_mesh), 2)

        return nodes
