from collections import defaultdict

from patch.include import *
from tqdm import tqdm


@app_context(commit=True)
def patch():
    """
    Здесь можно работать с моделями через models.CmfTask и т.д.
    Для прогрессбара используйте:
    for task in tqdm(models.CmfTask.list()):
        ...
    """
    # Выставим parent и cmf_deleted у объектов дерева проектов.
    tree_data = {}
    obj_index = {}
    children_index = defaultdict(list)

    print('Load data')
    for model in tqdm((
            models.CmfProject, models.CmfFolder, models.CmfList, models.CmfDocument,
            models.CmfActiveEntityFilter, models.CmfChatGroup)):
        model_data = tree_data.setdefault(model.class_name, {})
        for obj in model.list(
                fields=[
                    'cmf_deleted', 'parent_id', 'tree_parent_id', 'cmf_created_at', 'sys_type',
                    'cmf_owner.cmf_deleted'],
                include_deleted=True):
            model_data[obj.id.value] = obj
            obj_index[obj.id.value] = obj
            if obj.tree_parent_id:
                children_index[obj.tree_parent_id.value].append(obj)
                # if obj.parent_id:
                #     print('obj has parent and tree_parent', obj.id, obj.parent_id, obj.tree_parent_id)
            else:
                pass
                # print('object without tree parent', obj)

    print('Check parent')

    def get_parent(obj, deleted=None):
        """Получим parent из дерева"""
        if obj.tree_parent_id:
            tree_parent = obj_index[obj.tree_parent_id.value]
            return get_parent(tree_parent, deleted or tree_parent and tree_parent.cmf_deleted)
        if obj.class_name == 'CmfProject':
            return obj, deleted
        if obj.parent_id:
            parent = obj_index.get(obj.parent_id.value)
            return parent, deleted or parent and parent.cmf_deleted
        if obj.class_name == 'CmfFolder' and obj.sys_type == 'home':
            return obj.cmf_owner, deleted or obj.cmf_owner.cmf_deleted
        return None, deleted

    for obj in obj_index.values():
        if obj.class_name == 'CmfProject':
            continue  # не трогаем корни
        if obj.class_name == 'CmfFolder' and obj.sys_type == 'home':
            # if not obj.parent_id:
            #     print(f"{obj} ({obj.cmf_deleted}: {obj.cmf_created_at}): home dir without parent")
            continue
        parent, deleted = get_parent(obj)
        if parent:
            need_save = False
            if not obj.cmf_deleted and deleted:
                print(f'Delete {obj} as some parent deleted')
                obj.cmf_deleted = True
                need_save = True
            if obj.parent_id:
                pass
                # if obj.parent_id != parent.id:
                #     print(f"{obj} ({obj.cmf_deleted}: {obj.cmf_created_at}):"
                #           f" Parent by tree {parent} mismatch"
                #           f" current parent {obj_index.get(obj.parent_id) or obj.parent_id}")
            else:
                print(f'For {obj} (deleted: {obj.cmf_deleted}, created: {obj.cmf_created_at}): Set parent {parent}')
                obj.parent_id = parent.id
                need_save = True
            if need_save:
                obj.save(only_data=True)
        else:
            pass
            # if obj.tree_parent_id:
            #     print(f"{obj} ({obj.cmf_deleted}: {obj.cmf_created_at}):"
            #           f" Parent not found by tree parent {obj_index.get(obj.tree_parent_id) or obj.tree_parent_id}")
            # if not obj.parent_id:
            #     print(f"{obj} ({obj.cmf_deleted}: {obj.cmf_created_at}): no any parent")

    print('Создадим в проектах недостающие фильтры')
    for project in tqdm(models.CmfProject.list()):
        tags_set = set()
        for task in models.CmfTask.list(fields=['tags'], parent_id=project.id):
            tags_set.update(task.tags)
        project.hook_task_tags_changed(tags_set)
    # rollback_all_ds()


if __name__ == "__main__":
    patch()
