import bpy
from . import fn
from time import time, strftime
from pathlib import Path
import sys

from bpy.types import Panel, UIList, Operator, PropertyGroup, Menu
from bpy.props import PointerProperty, IntProperty, BoolProperty, StringProperty, EnumProperty, FloatProperty


class GPEXP_OT_render_all_scenes(bpy.types.Operator):
    bl_idname = "gp.render_all_scenes"
    bl_label = "Render all scenes"
    bl_description = "Render all scene except Render"
    bl_options = {"REGISTER"}

    @classmethod
    def poll(cls, context):
        return True

    def execute(self, context):
        start = time()
        ct = 0
        for scn in bpy.data.scenes:
            # if scn.name == 'Scene':
            #     continue
            if not scn.use_nodes:
                continue
            outfiles = [n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE']
            if not outfiles:
                print(f'\n -!-> Skip {scn.name}, No output files')
                continue

            if all(x.mute for x in outfiles):
                print(f'\n -!-> Skip {scn.name}, All output file are muted')
                continue

            print(f'\n --> Rendering {scn.name}')
            # bpy.context.window.scene = scn
            bpy.ops.render.render(animation=True, scene=scn.name)
            ct += 1

        print(f'\nDone. {ct} scenes rendered in {time()-start:.2f}s')
        return {"FINISHED"}


class GPEXP_scene_select_prop(PropertyGroup):
    name : StringProperty()
    select: BoolProperty()


def scene_render_popup_ui(self, context):
    layout = self.layout
    col = layout.column()
    for si in context.scene.scenes_list:
        row = col.row()
        row.prop(si, 'select',text='')
        row.label(text=si.name)

        ## Display warnings
        scn = bpy.data.scenes.get(si.name)
        # compare to existing Rlayers (overkill ?)
        # vls = [scn.view_layers.get(n.layer) for n in rlayers_nodes if scn.view_layers.get(n.layer)]

        vls = [vl for vl in scn.view_layers if vl.name != 'View Layer']

        if vls:
            exclude_count = len([vl for vl in vls if not vl.use])
            if exclude_count:
                row.label(text=f'{exclude_count}/{len(vls)} excluded viewlayers', icon='ERROR')

        if not scn.use_nodes:
            row.label(text='use_node deactivated', icon='ERROR')
            continue

        outfiles = [n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE']
        if not outfiles:
            row.label(text='No output files nodes', icon='ERROR')
            continue

        outnum = len(outfiles)
        muted = len([x for x in outfiles if x.mute])
        if muted == outnum:
            row.label(text='All output file are muted', icon='ERROR')
            continue

        elif muted:
            row.label(text=f'{muted}/{outnum} output file muted', icon='ERROR')
            continue

class GPEXP_OT_render_selected_scene(bpy.types.Operator):
    bl_idname = "gp.render_selected_scenes"
    bl_label = "Render Selected Scenes"
    bl_description = "Launch render of selected scenes with a selection popup"
    bl_options = {"REGISTER"}

    @classmethod
    def poll(cls, context):
        return bpy.data.is_saved

    def invoke(self, context, event):
        # if not bpy.data.is_saved:
        #     self.report({'ERROR'}, 'File needs to be saved')
        #     return {'CANCELLED'}
        context.scene.scenes_list.clear()
        for s in bpy.data.scenes:
            scn_item = context.scene.scenes_list.add()
            scn_item.name = s.name
            scn_item.select = s.name != 'Scene'

        return context.window_manager.invoke_props_dialog(self, width=250)

    def draw(self, context):
        ## Basic (without hints)
        # layout = self.layout
        # col = layout.column()
        # for si in context.scene.scenes_list:
        #     row = col.row()
        #     row.label(text=si.name)
        #     row.prop(si, 'select',text='')

        scene_render_popup_ui(self, context)

    def execute(self, context):
        d = fn.export_crop_to_json()
        if not d:
            print('No crop to export, border disabled in all scenes')

        scn_to_render = [si.name for si in context.scene.scenes_list if si.select]
        start = time()
        ct = 0
        for scn_name in scn_to_render:
            scn = bpy.data.scenes.get(scn_name)
            if not scn.use_nodes:
                print(f'{scn.name} has use node deactivated')
                continue

            outfiles = [n for n in scn.node_tree.nodes if n.type == 'OUTPUT_FILE']
            if not outfiles:
                print(f'\n -!-> Skip {scn.name}, No output files')
                continue

            if all(x.mute for x in outfiles):
                print(f'\n -!-> Skip {scn.name}, All output file are muted')
                continue

            print(f'\n --> Rendering {scn.name}')
            # bpy.context.window.scene = scn # no need
            bpy.ops.render.render(animation=True, scene=scn.name)
            ct += 1

        print(f'\nDone. {ct} scenes rendered in {time()-start:.2f}s')
        return {"FINISHED"}


class GPEXP_OT_bg_render_script_selected_scene(bpy.types.Operator):
    bl_idname = "gp.bg_render_script_selected_scenes"
    bl_label = "Create Selected Scene Render Batch "
    bl_description = "Create a batch script to render all selected scenes in a selection popup"
    bl_options = {"REGISTER"}

    @classmethod
    def poll(cls, context):
        return bpy.data.is_saved

    def invoke(self, context, event):
        context.scene.scenes_list.clear()
        for s in bpy.data.scenes:
            scn_item = context.scene.scenes_list.add()
            scn_item.name = s.name
            scn_item.select = s.name != 'Scene'

        return context.window_manager.invoke_props_dialog(self, width=500)

    def draw(self, context):
        scene_render_popup_ui(self, context)


    def execute(self, context):
        d = fn.export_crop_to_json()
        if not d:
            print('No crop to export, border disabled in all scenes')

        platform = sys.platform

        blend = Path(bpy.data.filepath)

        scn_to_render = [si.name for si in context.scene.scenes_list if si.select]
        batch_file = blend.parent / f'{blend.stem}--{len(scn_to_render)}batch_{strftime("%m-%d_%H-%M")}.sh'

        if platform.startswith('win'):
            script_text = ['@ECHO OFF']
            batch_file =  batch_file.with_suffix('.bat')
        else:
            script_text = ['#!/bin/bash']

        print('batch_file: ', batch_file)
        bin_path = bpy.app.binary_path
        for scn_name in scn_to_render:
            if platform.startswith('win'):
                import re
                pattern = r'users[\/\\](.*?)[\/\\]softs' # or point to user dit with %UserProfile%
                re_user = re.search(pattern, bin_path, re.I)
                if not re_user:
                    cmd = f'"{bin_path}" -b "{bpy.data.filepath}" -S "{scn_name}" -a'
                else:
                    bin_path = bin_path.replace(re_user.group(1), '%USERNAME%')
                    cmd = f'"{bin_path}" -b "{bpy.data.filepath}" -S "{scn_name}" -a'

            else: # Unix : point same for each user
                cmd = f'"{bin_path}" -b "{bpy.data.filepath}" -S "{scn_name}" -a'
            script_text.append(cmd)


        script_text.append('echo --- END BATCH ---')
        script_text.append('pause')

        with batch_file.open('w') as fd:
            fd.write('\n'.join(script_text))

        print(f'Using following binary path: {bin_path}')

        self.report({'INFO'}, f'Batch script generated: {batch_file}')
        return {"FINISHED"}

classes=(
GPEXP_scene_select_prop,
GPEXP_OT_render_selected_scene,
GPEXP_OT_render_all_scenes,
GPEXP_OT_bg_render_script_selected_scene,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    bpy.types.Scene.scenes_list = bpy.props.CollectionProperty(type=GPEXP_scene_select_prop)

def unregister():
    for cls in reversed(classes):
        bpy.utils.unregister_class(cls)

    del bpy.types.Scene.scenes_list