import bpy
import bgl

from .drawing_manager import DrawingManager
from .utils import render_debug
from .bgl_ext import create_framebuffer, glCheckError
from ..wbs_kernel.render import OpenGLUtils


class WoWRenderEngine(bpy.types.RenderEngine):
    # These three members are used by blender to set up the
    # RenderEngine; define its internal name, visible name and capabilities.
    bl_idname = "WOW"
    bl_label = "WoW"
    bl_use_preview = False
    bl_use_eevee_viewport = True

    # Init is called whenever a new render engine instance is created. Multiple
    # instances may exist at the same time, for example for a viewport and final
    # render.
    def __init__(self):

        self.glew_init = False
        self.first_time = True
        self.draw_manager = DrawingManager(bpy.context)

        render_debug('Instantiated render engine.')

    # When the render engine instance is destroy, this is called. Clean up any
    # render engine data here, for example stopping running render threads.
    def __del__(self):
        render_debug('Freed render engine.')

    # This is the method called by Blender for both final renders (F12) and
    # small preview for materials, world and lights.
    def render(self, depsgraph):
        scene = depsgraph.scene
        scale = scene.render.resolution_percentage / 100.0
        self.size_x = int(scene.render.resolution_x * scale)
        self.size_y = int(scene.render.resolution_y * scale)

        # Fill the render result with a flat color. The framebuffer is
        # defined as a list of pixels, each pixel itself being a list of
        # R,G,B,A values.
        if self.is_preview:
            color = [0.1, 0.2, 0.1, 1.0]
        else:
            color = [0.2, 0.1, 0.1, 1.0]

        pixel_count = self.size_x * self.size_y
        rect = [color] * pixel_count

        # Here we write the pixel values to the RenderResult
        result = self.begin_result(0, 0, self.size_x, self.size_y)
        layer = result.layers[0].passes["Combined"]
        layer.rect = rect
        self.end_result(result)

    # For viewport renders, this method gets called once at the start and
    # whenever the scene or 3D viewport changes. This method is where data
    # should be read from Blender in the same thread. Typically a render
    # thread will be started to do the work while keeping Blender responsive.
    def view_update(self, context, depsgraph):
        # depsgraph = context.evaluated_depsgraph_get()

        if not self.glew_init:
            OpenGLUtils.init_glew()
            self.glew_init = True

        region = context.region
        view3d = context.space_data
        scene = depsgraph.scene

        # Get viewport dimensions
        dimensions = region.width, region.height

        if self.first_time:
            self.first_time = False
            self.draw_manager.init_datablocks(depsgraph)
        else:
            self.draw_manager.update_render_data(depsgraph)

        '''
        # Loop over all object instances in the scene.
        if first_time or depsgraph.id_type_updated('OBJECT'):
            for instance in depsgraph.object_instances:
                pass
                
        '''

        render_debug('Num unfreed materials: {}\n'
                     'Num unfreed drawing objects: {}\n'
                     'Num unfreed batches: {}\n'.format(
            len(self.draw_manager.draw_materials),
            len(self.draw_manager.m2_objects),
            len(self.draw_manager.draw_elements.batches))
        )

    # For viewport renders, this method is called whenever Blender redraws
    # the 3D viewport. The renderer is expected to quickly draw the render
    # with OpenGL, and not perform other expensive work.
    # Blender will draw overlays for selection and editing on top of the
    # rendered image automatically.

    def view_draw(self, context, depsgraph):

        # buf = bgl.Buffer(bgl.GL_INT, 1)
        # bgl.glGetIntegerv(bgl.GL_FRAMEBUFFER_BINDING, buf)
        # cur_fbo = buf.to_list()[0]
        # del buf
        #
        # region = context.region
        # view3d = context.space_data
        # scene = depsgraph.scene
        #
        # # Get viewport dimensions
        # width, height = region.width, region.height
        #
        # bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, self.fbo_id)

        #bgl.glEnable(bgl.GL_BLEND)
        #bgl.glBlendFunc(bgl.GL_ONE, bgl.GL_ONE_MINUS_SRC_ALPHA)
        #self.bind_display_space_shader(context.scene)

        self.draw_manager.draw()

        bgl.glColorMask(False, False, False, True)
        bgl.glClearColor(0, 0, 0, 1.0)
        bgl.glClear(bgl.GL_COLOR_BUFFER_BIT)

        #self.unbind_display_space_shader()
        #bgl.glDisable(bgl.GL_BLEND)

        # glCheckError('post-draw-all')
        #
        # bgl.glBindFramebuffer(bgl.GL_DRAW_FRAMEBUFFER, cur_fbo)
        # bgl.glDrawBuffer(bgl.GL_BACK)
        #
        # bgl.glBindFramebuffer(bgl.GL_READ_FRAMEBUFFER, self.fbo_id)
        # bgl.glReadBuffer(bgl.GL_COLOR_ATTACHMENT0)
        #
        # glCheckError('bind fbos')
        #
        # bgl.glBlitFramebuffer(
        #                   0, 0, width, height,
        #                   0, 0, width, height,
        #                   bgl.GL_COLOR_BUFFER_BIT | bgl.GL_DEPTH_BUFFER_BIT,
        #                   bgl.GL_NEAREST)
        #
        # glCheckError('blit')
        #
        # bgl.glBindFramebuffer(bgl.GL_FRAMEBUFFER, cur_fbo)


# RenderEngines also need to tell UI Panels that they are compatible with.
# We recommend to enable all panels marked as BLENDER_RENDER, and then
# exclude any panels that are replaced by custom panels registered by the
# render engine, or that are not supported.
def get_panels():
    exclude_panels = {
    }

    panels = []
    for panel in bpy.types.Panel.__subclasses__():
        if hasattr(panel, 'COMPAT_ENGINES'): # and 'BLENDER_RENDER' in panel.COMPAT_ENGINES:
            if panel.__name__ not in exclude_panels:
                panels.append(panel)

    return panels


""" def register():
    # Register the RenderEngine
    bpy.utils.register_class(WoWRenderEngine)

    for panel in get_panels():
        panel.COMPAT_ENGINES.add('WOW')


def unregister():
    bpy.utils.unregister_class(WoWRenderEngine)

    for panel in get_panels():
        if 'WOW' in panel.COMPAT_ENGINES:
            panel.COMPAT_ENGINES.remove('WOW')


if __name__ == "__main__":
    register() """