from collections import defaultdict

from patch.include import *
from tqdm import tqdm

from sqlalchemy import update
from common.models.cmf_active_entity import CmfActiveEntity


@app_context(commit=True)
def patch():
    """
    Здесь можно работать с моделями через models.CmfTask и т.д.
    Для прогрессбара используйте:
    for task in tqdm(models.CmfTask.list()):
        ...
    """
    def status_key(status_):
        return \
            status_.name.value or '', status_.cmf_model.value or '', status_.cmf_model_activity_id.value or '',
        # status_.status_type.value

    def sort_key(it):
        if status_ := status_idx.get(it[0]):
            status_key_ = status_key(status_)
            result = status_key_, 1000000 - len(it[1])
        else:
            result = ('',), 0
        # print(f'compare {result}')
        return result

    def union_dup(dup_status, base_status):
        print(f'  union_dup({dup_status}, {base_status})')
        for status_opt in status_opts_by_status.get(dup_status.id.value) or []:
            print(f'    fix {status_opt} for {status_opt.work_list}')
            status_opt.status = base_status
            status_opt.save(only_data=True)

        for obj in usages.get(dup_status.id.value) or []:
            print(f'    fix {obj}')
            obj.status = base_status
            obj.cache_status_type = base_status.status_type
            obj.save(only_data=True)
        dup_status.delete(force=True)

    status_dups = defaultdict(list)
    status_idx = {}
    usages = defaultdict(list)
    for status in models.CmfStatus.list(fields=['*', 'status']):
        status_idx[status.id.value] = status
        status_dups[status_key(status)].append(status)
        usages[status.id.value]
    status_opts = models.CmfStatusOpt.list(fields=['*', 'work_list'])
    status_opts_by_status = defaultdict(list)
    for status_opt in status_opts:
        if status_opt.status_id:
            status_opts_by_status[status_opt.status_id.value].append(status_opt)

    for model_cls in CmfActiveEntity.iter_subclasses():
        print(f'Process {model_cls.class_name}')
        for obj in model_cls.list(fields=['status_id']):
            usages[obj.status_id.value].append(obj)

    prev_key = None
    first_status = None
    for status_id, obj_list in sorted(usages.items(), key=sort_key):
        status = status_idx.get(status_id)
        if not status:
            continue
        status_dups_count = len(status_dups[status_key(status)])
        if status_dups_count <= 1:
            continue
        print()
        print(f'{status_id} {len(obj_list):>5d} {status.name} {status.status_type} {status_dups_count}')
        key = status_key(status)
        if key == prev_key:
            union_dup(status, first_status)
        else:
            first_status = status
            prev_key = key


if __name__ == "__main__":
    patch()
