import prime_link_knot_10
import group_diagram_combination
from pd_code_components import get_components_from_pd_code # 求连通分支
import functools

try:
    from .get_version import get_version
except:
    from get_version import get_version

# 给定链环名称计算链环 pd_code
@functools.cache
def get_pd_code_from_link_name(link_name:str) -> list[list[int]]:
    pd_code = prime_link_knot_10.load_pd_code()[link_name]
    return pd_code

# 给出链环名称计算连通分量个数
@functools.cache
def get_components_cnt_from_link_name(link_name:str) -> int:
    return len(get_components_from_pd_code(
        get_pd_code_from_link_name(link_name))) # type: ignore

# 针对一个扭结组合生成连接方案
def gen_for_one_solution(sol:list[str], more_comment:list[str]=[]) -> list[str]:
    ans = []
    number_in_cluster = []
    for link_name in sol:
        number_in_cluster.append(get_components_cnt_from_link_name(link_name))
    
    # 生成注释
    comment = f"// automatically generated by com-link-gen-10 (version:{get_version("com-link-gen-10")})\n"
    if more_comment != []:
        for line in more_comment:
            if line.strip() != "":
                comment += f"// {line.strip().replace("\n", " ")}\n"

    # 构建 pd_code 描述序列
    pd_code_list = "".join([
        f"{link_name}: {get_pd_code_from_link_name(link_name)}\n"
        for link_name in (
            prime_link_knot_10.sort_link_name_list(list(set(sol)))) # 需要去重
    ])

    # 生成扭结集合
    knot_set = "[" + (", ".join(sol)) + "]\n"

    # 生成边组合方式
    edge_solution_list = group_diagram_combination.main(number_in_cluster, len(sol) - 1)
    for edge_solution in edge_solution_list:
        link_method = "".join([
            f"L[{edge[0][0]}, {edge[0][1]}]#L[{edge[1][0]}, {edge[1][1]}]\n"
            for edge in edge_solution
        ])
        ans.append(comment + pd_code_list + knot_set + link_method)
    return ans

# 针对所有扭结组合，生成所有连接方案
def gen_all_solution(
        sol_list:list[list[str]], more_comment:list[str]=[]) -> list[str]:
    
    arr = []
    for sol in sol_list:
        arr += gen_for_one_solution(sol, more_comment)
    return arr

# 生成所有
def com_link_gen(total_crs:int, max_component_cnt:int) -> list[str]:
    if total_crs >= 11: # 目前尚不支持大于等于 11 crossing 的方案
        raise ValueError()
    if total_crs <= 1: # 我们默认链环最简形式有大于等于两个交叉点（不考虑多个圈）
        raise ValueError()
    sol_list = prime_link_knot_10.get_all_combination(total_crs)
    sol_list = [
        sol
        for sol in sol_list
        if len(sol) <= max_component_cnt
    ]
    return gen_all_solution(sol_list, [
        f" - command: com_link_gen({total_crs}, {max_component_cnt})"
    ])

if __name__ == "__main__":
    print(com_link_gen(10, 3)[0])
