import bpy

# https://blenderartists.org/t/how-to-execute-operator-once-when-keymap-is-held-down/1166009
class GPTB_OT_temp_cutter(bpy.types.Operator):
    bl_idname = "wm.temp_cutter"
    bl_label = "Temporary cutter"
    bl_description = "Temporary cutter during press in GP mode"
    bl_options = {'REGISTER'}#, 'UNDO' avoid register undo step

    _is_running = False# block subsequent 'PRESS' events
    bpy.types.Scene.tmp_cutter_org_mode = bpy.props.StringProperty(
        name="temp cutter previous mode", description="Use to store mode used before cutter", default="")
    # original_mode = None

    def execute(self, context):
        print('exe so cute')
        bpy.ops.wm.tool_set_by_id(name='builtin.cutter')
        return {'FINISHED'}

    def invoke(self, context, event):
        if event.value == 'RELEASE':
            __class__._is_running = False
            
            # if self.original_mode:
            #     bpy.ops.wm.tool_set_by_id(name = self.original_mode)
            if context.scene.tmp_cutter_org_mode:
                bpy.ops.wm.tool_set_by_id(name = context.scene.tmp_cutter_org_mode)
                # self.original_mode = None

            # return 'CANCELLED' unless the code is important,
            # this prevents updating the view layer unecessarily
            return {'CANCELLED'}


        elif event.value == 'PRESS':
            if not self._is_running:
                # self.original_mode = bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False).idname
                context.scene.tmp_cutter_org_mode = bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False).idname
                
                __class__._is_running = True
                return self.execute(context)

        return {'CANCELLED'}

class GPTB_OT_sticky_cutter(bpy.types.Operator):
    bl_idname = "wm.sticky_cutter"
    bl_label = "Sticky cutter"
    bl_description = "Sticky cutter tool"
    bl_options = {'REGISTER'}#, 'UNDO'

    def execute(self, context):
        # toggle code
        # if self.original_mode == 'builtin.cutter':#if on cutter, return to draw
            # bpy.ops.wm.tool_set_by_id(name='builtin_brush.Draw')
        return {'FINISHED'}

    def modal(self, context, event):
        if event.type == self.key and event.value == 'PRESS':
            return {'RUNNING_MODAL'}
        
        elif event.type == self.key and event.value == 'RELEASE':
            
            if self.timeout:
                # use release code in here
                bpy.ops.wm.tool_set_by_id(name=self.original_mode)
                print("released")
                return {'FINISHED'}
            
            wm = context.window_manager
            wm.event_timer_remove(self.handler)
            # return {'FINISHED'}
            return self.execute(context)
            
        elif event.type == 'TIMER':
            self.timeout = True
            wm = context.window_manager
            wm.event_timer_remove(self.handler)

        if self.timeout:
            pass
            # print("repeating holding down") 
            # use holding down code in here
            # bpy.ops.wm.tool_set_by_id(name='builtin.cutter')#builtin.cutter cursor

        return {'PASS_THROUGH'}
            
    def invoke(self, context, event):
        self.key = ''
        #get key from keymap
        wm = bpy.context.window_manager
        #addons : #wm.keyconfigs.addon.keymaps.items()
        for cat, keymap in wm.keyconfigs.user.keymaps.items():#user set
            for k in keymap.keymap_items:
                if k.idname == 'wm.sticky_cutter':
                    self.key = k.type
        if not self.key:
            self.report({'ERROR'}, 'Could not found dedicated key in user keymap for "wm.sticky_cutter"')
            return {'CANCELLED'}

        self.original_mode = bpy.context.workspace.tools.from_space_view3d_mode(bpy.context.mode, create=False).idname
        if event.value == 'PRESS':
            self.timeout = False
            wm = context.window_manager
            wm.modal_handler_add(self)
            bpy.ops.wm.tool_set_by_id(name='builtin.cutter')
            self.handler = wm.event_timer_add(
                time_step=0.2, window=context.window)
            return {'RUNNING_MODAL'}
        return {'CANCELLED'}


## keymaps
'''
tmp_cutter_addon_keymaps = []
def register_keymaps():
    # pref = get_addon_prefs()
    # if not pref.temp_cutter_use_shortcut:
    #     return

    addon = bpy.context.window_manager.keyconfigs.addon

    try:
        km = bpy.context.window_manager.keyconfigs.addon.keymaps["3D View"]# Grease Pencil
    except Exception as e:
        km = addon.keymaps.new(name = "3D View", space_type = "VIEW_3D") #3D View
        pass

    ops_id = 'wm.temp_cutter'# 'wm.sticky_cutter'
    if ops_id not in km.keymap_items:
        ## keymap to operator cam space (in grease pencil mode only ?)
        km = addon.keymaps.new(name='3D View', space_type='VIEW_3D')#EMPTY #Grease Pencil #3D View

        # use 'ANY' to map both 'PRESS' and 'RELEASE' to the operator
        # then use the operator's invoke to deal with each articulation 
        kmi = km.keymap_items.new(ops_id, type="T", value="ANY")#, alt=pref.use_alt, ctrl=pref.use_ctrl, shift=pref.use_shift, any=False)
        tmp_cutter_addon_keymaps.append(km)

def unregister_keymaps():
    # wm = bpy.context.window_manager
    for km in tmp_cutter_addon_keymaps:
        for kmi in km.keymap_items:
            km.keymap_items.remove(kmi)
        # wm.keyconfigs.addon.keymaps.remove(km)#dont use new km field...
    tmp_cutter_addon_keymaps.clear()
    # del tmp_cutter_addon_keymaps[:]
'''

def register():
    if not bpy.app.background:
        bpy.utils.register_class(GPTB_OT_temp_cutter)
        bpy.utils.register_class(GPTB_OT_sticky_cutter)
        # register_keymaps()

def unregister():
    if not bpy.app.background:
        # unregister_keymaps()
        bpy.utils.unregister_class(GPTB_OT_temp_cutter)
        bpy.utils.unregister_class(GPTB_OT_sticky_cutter)


if __name__ == "__main__":
    register()