from patch.include import *
from tqdm import tqdm


def get_priority_schemes(file_path):
    with open(file_path, "r+") as f:
        for row in f:
            yield json.loads(row)


def fix_priority_config(project_ext_id, project_key, priority_schemes_file):
    priority_ids = []
    choices = {}
    default_id = None

    for priority_scheme in get_priority_schemes(priority_schemes_file):
        if project_key not in priority_scheme["projectKeys"]:
            continue
        default_id = priority_scheme.get("defaultOptionId")
        for priority in priority_scheme['priorities']:
            priority_name = priority["name"]
            priority_id = priority["id"]
            choices[priority_id] = priority_name
            priority_ids.append(int(priority_id))
        break

    cust_field_confs = models.CmfCustFieldConf.list(
        filter=["ext_id", "ILIKE", f"{project_ext_id}%"]
    )
    for cust_field_conf in cust_field_confs:
        cust_field_conf_field = models.CmfCustFieldConfField.get(
            filter=[
                ["name", "=", "priority"],
                ["parent", "=", cust_field_conf],
                ["cmf_import", "!=", None],
            ],
            fields=[
                "choices",
                "default",
            ]
        )
        if (
            not cust_field_conf_field
            or not cust_field_conf_field.import_original
        ):
            continue
        cust_field_conf_field.choices = choices
        cust_field_conf_field.default = {"value": default_id or "_NONE_"}
        if cust_field_conf_field.is_changed:
            cust_field_conf_field.save(save_import=True)
    cmf_commit()

    return priority_ids


def fix_task_priorities(project, priority_ids):
    task_filter = [
        ["project", "=", project],
        ["cmf_import", "!=", None],
    ]
    task_count = models.CmfTask.count(filter=task_filter)
    step = 100
    for i in tqdm(range(0, task_count, step)):
        tasks = models.CmfTask.list(
            filter=task_filter,
            fields=[
                "import_raw_json",
                "priority",
            ],
            slice=[i, i + step]
        )
        for task in tasks:
            try:
                task_data = task.import_raw_json.value
                if not task.import_original or not task_data:
                    continue
                priority_id = int(task_data["fields"]["priority"]["id"])
                priority_name = task_data["fields"]["priority"]["name"]
                if priority_id not in priority_ids:
                    print(
                        f"Ошибка в задаче {task}: "
                        f"приоритет '{priority_name}' ({priority_id}) "
                        f"недоступен для проекта {project}"
                    )
                    continue
                task.priority = priority_id
                if task.is_changed:
                    task.save(only_data=True)
            except Exception as exc:
                print(exc)
        cmf_commit()


@app_context(commit=True)
def fix_imported_priorities():
    """
    Патч исправляет конфигурацию приоритетов и приоритеты в задачах проекта
    Для тестирования патча: ( cd /opt/eva-app; python3 -m patch.fix_imported_priorities 'project_identifier' )
    """
    if len(sys.argv) > 1:
        project_identifier = sys.argv[1]
    else:
        raise Exception(
            "Проект не указан. Укажите код, префикс кода задач, название или ext_id проекта."
            "Например: python3 -m patch.fix_imported_priorities 'Example Project'"
        )
    print(f"Запуск патча fix_imported_priorities проекта '{project_identifier}'")

    project = models.CmfProject.get(
        filter=[
            [
                "OR",
                ["ext_id", "LIKE", f"%{project_identifier}%"],
                ["code", "=", project_identifier],
                ["task_code_prefix", "=", project_identifier],
                ["name", "=", project_identifier],
            ],
            ["cmf_import", "!=", None],
        ],
        fields=[
            "cmf_import.plugin",
            "import_raw_json",
        ],
    )
    if not project:
        raise Exception(f"Проект '{project_identifier}' не найден")
    if not project.import_raw_json:
        raise Exception(f"Проект {project} не содержит данных дампа")
    project_data = project.import_raw_json.value

    project_dir = project_data.get("project_dir")
    if not project_dir:
        raise Exception(
            f"В данных дампа проекта {project} отсутствует путь до каталога дампа"
        )

    project_path = Path(project_dir)
    source_hash_dir = project_path.parents[1]
    priority_schemes_file = source_hash_dir.joinpath("priority_schemes.json")
    if not priority_schemes_file.exists():
        raise Exception("Отсутствует дамп схемы приоритетов")

    source_hash = source_hash_dir.name
    project_id = project_data["id"]
    project_key = project_data["key"]
    project_ext_id = f"{source_hash}::{project_id}"

    priority_ids = fix_priority_config(project_ext_id, project_key, priority_schemes_file)
    fix_task_priorities(project, priority_ids)


if __name__ == "__main__":
    fix_imported_priorities()
