'''
Файл, содержащий скрипт для обработки и упрощения матрицы смежности. Запускается через команду в основном меню верстака freecad
'''


import json
import FreeCAD as App
from geometric_feasibility_predicate.main import main as asm_analysis
from constraints_operator import collect_assembly_settings
from clusterisation_sequences import ClusterisationSequenceUseCase


# === Для работы с json-файлами. Работает. ===
def simplify_adjacency_matrix_json(assembly_file, adjacency_file, output_file):
    def load_json(file_path):
        with open(file_path, 'r', encoding='utf-8') as file:
            return json.load(file)

    def save_json(file_path, data):
        with open(file_path, 'w', encoding='utf-8') as file:
            json.dump(data, file, ensure_ascii=False, indent=4)

    assembly_settings = load_json('/assembly_settings.json')
    adjacency_matrix = load_json('/adjacency_matrix.json')

    fasteners = set()
    for item in assembly_settings:
        if item.get("Type") == "fastener_set":
            fasteners.add(item["Parent"])
            fasteners.add(item["Child"])

    simplified_matrix = {
        "allParts": [],
        "matrix": {}
    }

    for part in adjacency_matrix["allParts"]:
        if part not in fasteners:
            simplified_matrix["allParts"].append(part)
            neighbors = [
                neighbor for neighbor in adjacency_matrix["matrix"].get(part, [])
                if neighbor not in fasteners
            ]
            if neighbors or part not in fasteners:
                simplified_matrix["matrix"][part] = neighbors

    save_json(output_file, simplified_matrix)


# simplify_adjacency_matrix('assembly_settings.json', 'adjacency_matrix.json', 'simplified_adjacency_matrix.json')


def restore_full_sequence_json(assembly_file, sequence_file, output_file):
    def load_json(file_path):
        with open(file_path, 'r', encoding='utf-8') as file:
            return json.load(file)

    def save_json(file_path, data):
        with open(file_path, 'w', encoding='utf-8') as file:
            json.dump(data, file, ensure_ascii=False, indent=4)

    assembly_settings = load_json(assembly_file)
    sequence = load_json(sequence_file)

    full_sequence = []
    sequence_set = set(sequence)

    for item in sequence:
        full_sequence.append(item)
        for setting in assembly_settings:
            if setting.get("Type") == "fastener_set":
                parent = setting["Parent"]
                child = setting["Child"]
                if parent in sequence_set and child in sequence_set:
                    full_sequence.append(setting["Fasteners"])
    
    save_json(output_file, full_sequence)


# restore_full_sequence('assembly_settings.json', 'sequence.json', 'full_sequence.json')


# ==== Для работы с внутренними переменными

def simplify_adjacency_matrix(assembly_settings, adjacency_matrix):
    fasteners = set()
    for item in assembly_settings:
        if item.get("Type") == "fastener_set":
            fasteners.add(item["Parent"])
            fasteners.add(item["Child"])

    simplified_matrix = {
        "allParts": [],
        "matrix": {}
    }

    for part in adjacency_matrix["allParts"]:
        # Добавляем все детали, включая крепеж, в simplified_matrix["allParts"]
        simplified_matrix["allParts"].append(part)
        
        # Получаем соседей, исключая только крепежные элементы
        neighbors = [
            neighbor for neighbor in adjacency_matrix["matrix"].get(part, [])
            if neighbor not in fasteners
        ]
        
        # Если у части есть соседи, добавляем их в матрицу
        if neighbors:
            simplified_matrix["matrix"][part] = neighbors

    return simplified_matrix


def restore_full_sequence(assembly_settings, sequences):
    full_sequences = []

    for sequence in sequences:
        full_sequence = []
        sequence_set = set(sequence)

        # Сначала добавляем все детали в полную последовательность
        for item in sequence:
            full_sequence.append(item)

        # Теперь добавляем крепежные элементы после элемента с наибольшим порядковым номером
        for setting in assembly_settings:
            if setting.get("Type") == "fastener_set":
                parent = setting["Parent"]
                child = setting["Child"]
                fasteners = setting["Fasteners"]
                
                # Проверяем, если родитель и ребенок в последовательности
                if (parent in sequence_set) and (child in sequence_set):
                    # Находим индексы родителя и ребенка в полной последовательности
                    parent_index = full_sequence.index(parent)
                    child_index = full_sequence.index(child)

                    # Находим максимальный индекс между родителем и ребенком
                    max_index = max(parent_index, child_index)

                    # Проверяем, содержатся ли крепежные элементы уже в последовательности
                    if not any(fastener in full_sequence for fastener in fasteners):
                        # Добавляем крепежные элементы после элемента child
                        full_sequence[max_index + 1:max_index + 1] = fasteners

        full_sequences.append(full_sequence)

    return full_sequences







def main():

    App.open('/home/markvoltov/GitProjects/framework/test_models/test_reductor.FCStd')
    if App.ActiveDocument:
        intersection_geometry, sequences, topologyMatrix = asm_analysis()

        assembly_settings = collect_assembly_settings()
        print(assembly_settings)     
        simplified_matrix = simplify_adjacency_matrix(assembly_settings, topologyMatrix)

        assembly_sequences = ClusterisationSequenceUseCase().call(topologyMatrix['matrix'])
        # print('Последовательности 1', assembly_sequences)
        assembly_sequences_simplified= ClusterisationSequenceUseCase().call(simplified_matrix['matrix'])
        # print('Последовательности 2',assembly_sequences_simplified)
        assembly_sequences_restored = restore_full_sequence(assembly_settings, assembly_sequences_simplified)
        print('Последовательности 3',assembly_sequences_restored)
    else:
        print('Ошибка. Нет активного документа!')

main()