
import sys
import bpy
from pathlib import Path
import os
from bone_widget.shape_utils import get_bone


class BW_context:
    def __init__(self):

        self.module_dir = Path(__file__).parent
        self.module_name = self.module_dir.name
        self.id_name = 'bonewidget'
        
        self._rig = None
        self._folder_items = []
        self.shapes = {} # used to store vert co for the transform properties

        os.chdir(self.module_dir/'widgets')

    @property
    def addon(self):
        from bpy import context
        return context.preferences.addons[__package__]

    @property
    def prefs(self):
        return self.addon.preferences

    #def settings(self):
    #    return bpy.context.window_manager.
    @property
    def show_transforms(self):
        ops = bpy.context.window_manager.operators
        id_names = [self.get_op_id(o) for o in ('transform_widget','create_widget', 'match_transform')]
        return (ops and ops[-1].bl_idname in id_names)

    @property
    def clean_widget_op(self):
        ops = bpy.context.window_manager.operators
        op_idname = self.get_op_id('clean_widget')

        #transforms = self.prefs.transforms
        if ops and ops[-1].bl_idname == op_idname:
            return ops[-1]

    # @property
    # def show_prefs_op(self):
    #     ops = bpy.context.window_manager.operators
    #     id_names = [
    #         self.get_op_id('show_preferences'),
    #         self.get_op_id('add_folder'),
    #         self.get_op_id('remove_folder')
    #     ]

    #     #transforms = self.prefs.transforms
    #     if ops and ops[-1].bl_idname in id_names:
    #         return True

    @property
    def category(self):
        if not self.prefs:
            return 'Rig'

        return self.prefs.category      

    @property
    def rig(self):
        bone = self.bone
        if bone:
            return bone.id_data

    @property
    def widget_col(self):
        col_name = self.prefs.collection

        col_name = col_name.format(ob=bpy.context.object)

        col = bpy.data.collections.get(col_name)
        if not col:
            col = bpy.data.collections.new(col_name)
            col.hide_viewport = True

        if col not in self.get_scene_cols():
            bpy.context.scene.collection.children.link(col)

        return col

    @property
    def widget_layer_col(self):
        return next((c for c in self.get_layer_cols() if c.collection == self.widget_col), None)

    @property
    def default_folder_path(self):
        return self.prefs.default_folder.abspath

    @property
    def custom_folder_paths(self):
        return [f.abspath for f in self.prefs.folders if f.path]

    @property
    def folder_paths(self):
        return [self.default_folder_path] + self.custom_folder_paths

    @property
    def folders(self):
        return list(self.prefs.folders) + [self.prefs.default_folder]

    @property
    def active_folder(self):
        folder = self.abspath(self.prefs.folder_enum)
        if folder == self.default_folder_path: 
            return self.prefs.default_folder
        else:
            return next((f for f in self.prefs.folders if f.abspath==folder), None)

    @property
    def active_widget(self):
        folder = self.active_folder
        if not folder:
            return 

        index = folder.widget_index
        return folder.active_widget

    @property
    def bone(self):
        if not self.poll():
            return

        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            return bpy.context.active_pose_bone
        else:
            return get_bone(ob)



    @property
    def bones(self):
        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            return list(ob.pose.bones)
        else:
            widgets = self.widgets
            return [b for b in self.rig.pose.bones if b.custom_shape in widgets]

    @property
    def selected_bones(self):
        if not self.poll():
            return []

        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            return bpy.context.selected_pose_bones
            #bones = ob.pose.bones
            #return [b for b in bones if b.bone.select]
        elif self.rig:
            widgets = self.selected_widgets
            return [b for b in self.rig.pose.bones if b.custom_shape in widgets]

        return []

    @property
    def widget(self):
        if not self.poll():
            return

        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            if bpy.context.active_pose_bone:
                return bpy.context.active_pose_bone.custom_shape
        else:
            return ob

    @property
    def widgets(self):
        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            return [b.custom_shape for b in self.bones if b.custom_shape]

    @property
    def selected_widgets(self):
        if not self.poll():
            return []

        ob = bpy.context.object
        if ob.type == 'ARMATURE':
            bones = self.selected_bones
            return [b.custom_shape for b in bones if b.custom_shape]
        else:
            objects = bpy.context.selected_objects
            return [o for o in objects if o.select_get() and o.type in ('MESH', 'CURVE')]

    @property
    def folder_items(self):
        for folder in self.folder_paths:
            if not any(self.abspath(f[0])==folder for f in self._folder_items):
                id = 0
                if self._folder_items:
                    id = max([i[-1] for i in self._folder_items])+1

                self._folder_items.append((str(folder), folder.name, '', '', id))

        for f in reversed(self._folder_items):
            if self.abspath(f[0]) not in self.folder_paths:
                self._folder_items.remove(f)
        
        return self._folder_items


    def get_flipped_bone(self, bone):
        pass

    #def get_bone(self, shape):
    #    armatures = [o for o in bpy.context.scene.objects if o.type == 'ARMATURE']
    #    return next((b for a in armatures for b in a.pose.bones if b.custom_shape == shape), None)

    def get_scene_cols(self, col=None, children=None):
        if children is None:
            children = set()
        if col is None:
            col = bpy.context.scene.collection

        for c in col.children:
            children.add(c)
            self.get_scene_cols(c, children)
        
        return list(children)

    def get_layer_cols(self, col=None, children=None):
        if children is None:
            children = set()
        if col is None:
            col = bpy.context.view_layer.layer_collection

        for c in col.children:
            children.add(c)
            self.get_layer_cols(c, children)
        
        return list(children)

    def abspath(self, path):
        if not path:
            return 

        if path.startswith('//'):
            path = './' + path[2:]

        return Path(path).absolute().resolve()

    def poll(self):
        ob = bpy.context.object
        if not ob:
            return False
        if ob.type == 'ARMATURE' and ob.mode == 'POSE':
            return True
        if ob.type in ('MESH', 'CURVE'):
            return True
        return False

    def store_shapes(self):
        self.shapes.clear()
        for widget in self.selected_widgets:
            coords = [0]*len(widget.data.vertices)*3
            widget.data.vertices.foreach_get('co', coords)
            self.shapes[widget] = coords

    def reset_transforms(self):
        transforms = self.prefs.transforms
        
        transforms['size'] = 1
        transforms['xz_scale'] = 1
        transforms['slide'] = 0
        transforms['loc'] = (0, 0, 0)
        transforms['rot'] = (0, 0, 0)
        transforms['scale'] = (1, 1, 1)

    def init_transforms(self):
        self.store_shapes()
        self.reset_transforms()

    def get_op_id(self, name):
        return f'{self.id_name.upper()}_OT_{name}'

    #def call(self, op):
    #    ops_data = getattr(bpy.ops, ctx.id_name)
    #    getattr(ops_data, op)()




