from . import g
from .loop import Loop
from collections import defaultdict

# 因为要引用Loop patch,所以单独放了


def regenerate_loops(is_force_refresh=False):
    boundaries = g.boundaries  # 假设 'g' 有一个 'boundaries' 属性，它包含边界对象
    graph = {}

    # 构建无向图
    for boundary in boundaries:
        graph.setdefault(boundary.start_vertex, []).append(boundary.end_vertex)
        graph.setdefault(boundary.end_vertex, []).append(boundary.start_vertex)

    # 方向字典
    boundary_direction = {
        (boundary.start_vertex, boundary.end_vertex): (boundary, True)
        for boundary in boundaries
    }
    boundary_direction.update(
        {
            (boundary.end_vertex, boundary.start_vertex): (boundary, False)
            for boundary in boundaries
        }
    )

    def dfs(node, start, path, visited, current_loops):
        max_length = 6
        if len(path) > max_length:
            return

        visited.add(node)
        path.append(node)

        for neighbor in graph[node]:
            # 2条边在拓扑结构上是一摸一样的，没办法通过拓扑办法识别最小圈
            if neighbor == start and len(path) > 2:
                # 找到一个环路，创建对应的环路（每条边是一个元组，包含boundary和方向）
                loop = Loop()
                for i in range(len(path) - 1):
                    start_vertex = path[i]
                    end_vertex = path[i + 1]
                    if (start_vertex, end_vertex) in boundary_direction:
                        boundary, direction = boundary_direction[
                            (start_vertex, end_vertex)
                        ]
                        loop.add_edge(boundary, direction)
                    else:
                        boundary, direction = boundary_direction[
                            (end_vertex, start_vertex)
                        ]
                        loop.add_edge(boundary, direction)

                # 处理闭合边（path[-1] 到 path[0]）
                start_vertex = path[-1]
                end_vertex = path[0]
                if (start_vertex, end_vertex) in boundary_direction:
                    boundary, direction = boundary_direction[(start_vertex, end_vertex)]
                    loop.add_edge(boundary, direction)
                else:
                    boundary, direction = boundary_direction[(end_vertex, start_vertex)]
                    loop.add_edge(boundary, direction)

                current_loops.append(loop)
            elif neighbor not in visited:
                dfs(neighbor, start, path, visited, current_loops)

        path.pop()
        visited.remove(node)

    loops = []  # 所有环路
    for node in graph:
        current_loops = []  # 用来存储当前节点发现的环路
        dfs(node, node, [], set(), current_loops)
        loops.extend(current_loops)  # 将当前节点的环路加入到结果中

    # 去重环路
    unique_loops = set(loops)  # 使用 set 去重环路

    # 删除长度超过6的
    unique_loops = {loop for loop in unique_loops if len(loop.boundaries) <= 6}

    # 如果一个环路，他有弦，则删掉
    to_be_delete_loops = set()

    # 获取连续1 2 3条boundary的映射，并且要标记属于哪个loop的
    start_v_and_end_v_to_loops_of_length = [
        defaultdict(set) for _ in range(3)
    ]  # 0是长度为1的，1为长度为2的，2为长度为3的，元素为字典，key是两个顶点，value是相关的loop
    for loop in unique_loops:
        verts = loop.controll_verts
        for vert_idx, vert in enumerate(verts):
            for offset in range(1, 4):  # 1~3
                vert_1 = verts[vert_idx]
                vert_2 = verts[(vert_idx + offset) % len(verts)]

                sorted_start_v_and_end_v_tuple = tuple(
                    sorted([vert_1, vert_2], key=lambda v: v.index)
                )
                start_v_and_end_v_to_loops_of_length[offset - 1][
                    sorted_start_v_and_end_v_tuple
                ].add(loop)

    # # debug形状
    # print(len(start_v_and_end_v_to_loops_of_length))
    # for i, start_v_and_end_v_to_loops in enumerate(
    #     start_v_and_end_v_to_loops_of_length
    # ):
    #     print(f"长度{i+1}")
    #     for (vert_1, vert_2), loops in start_v_and_end_v_to_loops.items():
    #         print(len(loops))

    for loop in unique_loops:
        if loop.length <= 3:  # 小于3不检查弦
            continue

        offset_range = loop.length - 3

        loop_controll_verts = loop.controll_verts

        for offset in range(1, offset_range + 1):
            # 隔一个顶点就检查1条的，隔两个顶点就检查1和2条的，隔三个就检查123条的
            # offset就是boundary的条数

            # 遍历两两不相邻的顶点
            for i in range(len(loop_controll_verts)):
                for j in range(len(loop_controll_verts)):
                    # 确保 j 不等于 i，并且 j 不是 i 的相邻边界
                    if (
                        i != j
                        and (j != (i + 1) % len(loop_controll_verts))
                        and (j != (i - 1) % len(loop_controll_verts))
                    ):
                        vert_1 = loop_controll_verts[i]
                        vert_2 = loop_controll_verts[j]
                        sorted_start_v_and_end_v_tuple = tuple(
                            sorted([vert_1, vert_2], key=lambda v: v.index)
                        )
                        # 隔一个顶点就检查1条的，2和3跳过
                        # 如果 i 和 j 隔了 1 个顶点，跳过 offset 为 1 和 2
                        distance = min(
                            abs(i - j), len(loop_controll_verts) - abs(i - j)
                        )  # 0 1距离1

                        # print(loop.length, distance, offset)

                        if distance == 2 and (offset == 2 or offset == 3):
                            continue  # 跳过 offset 为 1 或 2 的情况

                        # 如果 i 和 j 隔了 2 个顶点，跳过 offset 为 2
                        if distance == 3 and offset == 2:
                            continue  # 跳过 offset 为 2 的情况

                        related_loops = start_v_and_end_v_to_loops_of_length[
                            offset - 1
                        ].get(sorted_start_v_and_end_v_tuple)
                        if not related_loops:
                            continue
                        # 排除自身的影响，并且用-号而不用remove()这样搞不会导致start_v_and_end_v_to_loops_of_length被修改
                        remaining_loops = related_loops - {loop}
                        if remaining_loops:
                            to_be_delete_loops.add(loop)
                            # TODO:一旦被认为是弦，则对该loop的循环就要退出了，但是层数太多了
                            break

    # # 从所有的loops中删除外层loop
    unique_loops.difference_update(to_be_delete_loops)

    # 防止重建网格
    updated_loops = []
    if not is_force_refresh:
        loop_tobe_assign = set()
        for loop in unique_loops:
            if loop in g.loops:
                continue
            g.loops.append(loop)
            updated_loops.append(loop)
    else:
        g.loops = unique_loops
        updated_loops = unique_loops

    # print(len(g.loops))
    # for loop in g.loops:
    #     print("---")
    #     print(loop.shape)
    #     for b, d in loop.b_and_d_list:
    #         print(b.start_vertex.index, b.end_vertex.index, d)

    for updated_loop in updated_loops:
        updated_loop.recreate_pattern()

    return updated_loops
