import bpy, re
from . import fn

def check_broken_modifier_target(pool=None, reports=None):
    if not reports:
        reports = []
    if not pool:
        pool = [o for o in bpy.context.scene.objects if o.type == 'GPENCIL']

    for o in pool:
        lay_name_list = [l.info for l in o.data.layers]
        for m in o.grease_pencil_modifiers:
            if not hasattr(m, 'layer'):
                continue
            if not m.layer:
                continue
            if not m.layer in lay_name_list:
                reports.append(f'Broken modifier target :{o.name} > {m.name} > {m.layer}')
            # else:
            #     print(f'Modifier target :{o.name} > {m.name} > ok')

    return reports

def check_layer_state(pool=None, reports=None):
    if not reports:
        reports = []
    if not pool:
        pool = [o for o in bpy.context.scene.objects if o.type == 'GPENCIL']
    for ob in pool:
        layers = ob.data.layers
        for l in layers:
            # if l.mask_layers:
            #     if not any(not x.hide for x in l.mask_layers):
            #         # all masks disable
            #         pass

                ## just list masks
                # state = '' if l.use_mask_layer else ' (disabled)'
                # reports.append(f'{ob.name} > {l.info} masks{state}:')
                # for ml in l.mask_layers:
                #     mlstate = ' (disabled)' if ml.hide else ''
                #     mlinvert = ' <>' if ml.invert else ''
                #     reports.append(f' - {ml.name}{mlstate}{mlinvert}')

            if l.opacity != 1 and not l.info.startswith('MA_'):
                reports.append(f'{ob.name} > {l.info} > opacity {l.opacity}')

            # if l.use_lights:
            #     reports.append(f'-> use lights !')

            if l.blend_mode != 'REGULAR':
                reports.append(f'{ob.name} > {l.info} > blend mode "{l.blend_mode}" !')

    return reports

def check_file_output_numbering(reports=None):
    if not reports:
        reports = []
    prenum = re.compile(r'\d{3}_')
    file_outs = []
    for S in bpy.data.scenes:
        if not S.node_tree or not S.use_nodes: # S.name == 'Scene' or 
            continue
        file_outs += [n for n in S.node_tree.nodes if n.type == 'OUTPUT_FILE']

    if not file_outs:
        reports.append('No file output nodes found')
        return reports

    for fo in file_outs:
        ### Check for object prefix number in path
        split_path = fo.base_path.split('/')
        if not prenum.match(split_path[-1]):
            report_missing_number = True
            # No prefix-number in tail part name
            if len(split_path) >= 2 and prenum.match(split_path[-2]):
                # report if no prefix-number on parent path part either
                report_missing_number = False

            if report_missing_number:
                reports.append(f'No object numbering : node {fo.name}')

        pct = 0
        if fo.format.file_format == 'OPEN_EXR_MULTILAYER':
            ## multilayer use layer_slots > slot.name
            slots = fo.layer_slots
            for fs in slots:
                if not prenum.match(fs.name.split('/')[0]):
                    pct += 1
        else:
            ## classic use file_slots > path
            slots = fo.file_slots
            for fs in slots:
                if not prenum.match(fs.path.split('/')[0]):
                    pct += 1
        
        if pct:
            reports.append(f'{pct}/{len(slots)} slots not numbered: node {fo.name}')

    return reports
class GPEXP_OT_check_render_scene(bpy.types.Operator):
    bl_idname = "gp.check_render_scene"
    bl_label = "Check render scene"
    bl_description = "Auto check render scene"
    bl_options = {"REGISTER"} # , "UNDO"

    # clear_unused_view_layers : bpy.props.BoolProperty(name="Clear unused view layers",
    #     description="Delete view layer that aren't used in the nodetree anymore",
    #     default=True)

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

    def invoke(self, context, event):
        return self.execute(context)
        # return context.window_manager.invoke_props_dialog(self)

    # def draw(self, context):
    #     layout = self.layout
    #     # layout.prop(self, 'clear_unused_view_layers')

    def execute(self, context):
        reports = []
        # check gp modifiers
        broken_mods = check_broken_modifier_target()
        if broken_mods:
            reports.append('GP modifiers targets:')
            reports += broken_mods

        # check layers
        layer_state = check_layer_state()
        if layer_state:
            if reports: reports.append('')
            reports.append('Layers State:')
            reports += layer_state

        # check file output numbering
        numbering_problems = check_file_output_numbering()
        if numbering_problems:
            if reports: reports.append('')
            reports.append('File output numbering:')
            reports += numbering_problems

        if not reports:
            self.report({'INFO'}, 'All OK !')
            reports.append('Everything Ok !')

        if hasattr(bpy.types, 'GP_OT_file_checker'):
            # propose to run toolbox checker if exists
            reports.append(['gp.file_checker', 'Run GP_toolbox File Checker', 'SCENE_DATA'])

        fn.show_message_box(_message=reports, _title='Potential Problems list')
        return {"FINISHED"}

classes=(
GPEXP_OT_check_render_scene,
)

def register():
    for cls in classes:
        bpy.utils.register_class(cls)

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