function combine_union(g1::AbstractGraph, g2::AbstractGraph; kwargs...)
    g3 = union(g1, g2)
    cliques = maximal_cliques(cg)
    cliquetree, nb_lc = get_cliquetree(cliques)
    return cliques, cliquetree, g3, nb_lc, Dict()
end

function combine_intersect(g1, g2; dec_type::Symbol=:cholesky, kwargs...)
    g3 = intersect(g1, g2)
    if is_chordal(g3)
        cliques, cliquetree, nb_lc = get_decomposition_data(g3)
        return cliques, cliquetree, g3, nb_lc, Dict()
    else
        return decompose(g3, dec_type)
    end
end

function combine_intersect_dist(g1, g2)
    g3 = intersect(g1, g2)
    if is_chordal(g3)
        cliques, cliquetree, nb_lc = get_decomposition_data(g3)
        return cliques, cliquetree, g3, nb_lc, Dict()
    else
        miss_edges = union(setdiff(edges(g1), edges(g3)), setdiff(edges(g2), edges(g3)))
        while !isempty(miss_edges) || is_chordal(g3)
            @info "$(length(miss_edges))"
            dists = [length(a_star(g3, e.src, e.dst)) for e in miss_edges]
            ei = sortperm(dists)[1]
            add_edge!(g3, miss_edges[ei])
            deleteat!(miss_edges, ei)
        end
    end
end

function combine_intersect_percent(g1, g2; percent=0.1, dec_type::Symbol=:cholesky, kwargs...)
    g3 = intersect(g1, g2)
    if is_chordal(g3)
        cliques, cliquetree, nb_lc = get_decomposition_data(g3)
        return cliques, cliquetree, g3, nb_lc, Dict()
    else
        miss_edges_g1 = setdiff(edges(g1), edges(g3))
        miss_edges_g2 = setdiff(edges(g2), edges(g3))
        nb_edges_to_add_g1 = floor(Int, percent * length(miss_edges_g1))
        nb_edges_to_add_g2 = floor(Int, percent * length(miss_edges_g2))
        for e in sample(miss_edges_g1, nb_edges_to_add_g1, replace=false)
            add_edge!(g3, e)
        end
        for e in sample(miss_edges_g2, nb_edges_to_add_g2, replace=false)
            add_edge!(g3, e)
        end
        return decompose(g3, dec_type)
    end
end

# TODO: use Molzahn heuristic to choose which cliques to select
#function molzahn_heuristic_combination(cliques, clique, cliquetree_graph, dstmx)
#    add_vertex!(cliquetree_graph)
#    index = nv(cliquetree_graph)
#    set_prop!(cliquetree_graph, nv(cliquetree_graph), :clique, clique)
#    dstmx = hcat(dstmx, zeros(Int, size(dstmx)[1]))
#    dstmx = vcat(dstmx, zeros(Int, size(dstmx)[2]))
#    for v in vertices(cliquetree_graph)[begin:end - 1]
#        length_intersect = length(intersect(clique, get_prop(cliquetree_graph, v, :clique)))
#        if length_intersect > 0
#            add_edge!(cliquetree_graph, v, index)
#            dstmx[v, index] = length_intersect
#            dstmx[index, v] = length_intersect
#        end
#    end
#end

#function get_neighbor(cliques, clique)
#    neighbor = cliques[1]
#    neighbor_similarity = length(intersect(cliques[1], clique))
#    for c in cliques[2:end]
#        similarity = length(intersect(c, clique))
#        if similarity > neighbor_similarity
#            neighbor = c
#            neighbor_similarity = similarity
#        end
#    end
#    return neighbor
#end

function combine_cliques_intersect(g1, g2; instance_path, dec_type=:cholesky, kwargs...)
    cliques1 = sort(map(sort, maximal_cliques(g1)))
    cliques2 = sort(map(sort, maximal_cliques(g2)))
    cliques3 = intersect(cliques1, cliques2)
    isempty(cliques3) && return nothing
    g3 = construct_graph_from_cliques(cliques3)
    g3 = union(g3, construct_network_graph(instance_path))
    return decompose(g3, dec_type)
end

const combine_map = Dict(
    :union => combine_union,
    :intersect => combine_intersect,
    :intersect_percent => combine_intersect_percent,
    :intersect_cliques => combine_cliques_intersect
)

function combine_decomposition(g1::AbstractGraph, g2::AbstractGraph; combine_type::Symbol=:intersect, kwargs...)
    return combine_map[combine_type](g1, g2; kwargs...)
end
