annotate_go_with_representative_ancestor <- function(
    df,
    go_id_col = "ID",
    go_name_col = "Name",
    bp_general_blacklist = character(0),
    add_status = TRUE
) {
  if (!requireNamespace("GO.db", quietly = TRUE)) stop("请先安装 GO.db 包")
  if (!requireNamespace("AnnotationDbi", quietly = TRUE)) stop("请先安装 AnnotationDbi 包")
  if (!requireNamespace("dplyr", quietly = TRUE)) stop("请先安装 dplyr 包")

  stopifnot(
    go_id_col %in% colnames(df),
    go_name_col %in% colnames(df),
    is.character(bp_general_blacklist)
  )

  go_ids <- unique(df[[go_id_col]])
  bp_ancestor_map <- as.list(GO.db::GOBPANCESTOR)

  missing_ids <- setdiff(go_ids, names(bp_ancestor_map))
  if (length(missing_ids) > 0) {
    warning(length(missing_ids), " 个 GO ID 在 GOBPANCESTOR 中找不到（非 BP 本体或已废弃）: ",
            paste(head(missing_ids, 5), collapse = ", "))
  }
  
  anc_table <- lapply(go_ids, function(go) {
    anc <- bp_ancestor_map[[go]]
    if (is.null(anc)) return(NULL)
    data.frame(GOID = go, ancestor = anc, stringsAsFactors = FALSE)
  }) |> dplyr::bind_rows()
  
  # 显式移除根节点 "all" 和 GO:0008150（BP root）
  anc_table_filtered <- anc_table |>
    dplyr::filter(
      !ancestor %in% c("all", "GO:0008150"),
      !ancestor %in% bp_general_blacklist
    ) |>
    dplyr::distinct(GOID, ancestor)
  
  ancestor_freq <- anc_table_filtered |>
    dplyr::count(ancestor, name = "n_GO")
  
  anc_with_freq <- anc_table_filtered |>
    dplyr::left_join(ancestor_freq, by = "ancestor")
  
  go_top_ancestor <- anc_with_freq |>
    dplyr::group_by(GOID) |>
    dplyr::filter(n_GO == max(n_GO)) |>
    # 平局时取祖先数最多的（depth 越深 = 越具体），保证确定性且有生物学意义
    dplyr::mutate(anc_depth = lengths(bp_ancestor_map[ancestor])) |>
    dplyr::slice_max(anc_depth, n = 1, with_ties = FALSE) |>
    dplyr::ungroup() |>
    dplyr::select(GOID, ancestor)
  
  ancestor_term_map <- AnnotationDbi::select(
    GO.db::GO.db,
    keys = unique(go_top_ancestor$ancestor),
    keytype = "GOID",
    columns = "TERM"
  )
  ancestor_term_map <- ancestor_term_map |> dplyr::rename(ancestor_TERM = TERM)
  
  go_top_ancestor <- go_top_ancestor |>
    dplyr::left_join(
      ancestor_term_map,
      by = c("ancestor" = "GOID")
    )
  
  out <- df |>
    dplyr::left_join(
      go_top_ancestor,
      by = setNames("GOID", go_id_col)
    ) |>
    dplyr::mutate(
      ancestor_final = ifelse(
        is.na(ancestor),
        .data[[go_id_col]],
        ancestor
      ),
      ancestor_TERM_final = ifelse(
        is.na(ancestor_TERM),
        .data[[go_name_col]],
        ancestor_TERM
      )
    ) |>
    dplyr::select(-ancestor, -ancestor_TERM)
  
  if (add_status) {
    out <- out |>
      dplyr::mutate(
        ancestor_status = ifelse(
          ancestor_final == .data[[go_id_col]],
          "standalone_GO_term_no_informative_ancestor",
          "assigned_to_representative_ancestor"
        )
      )
  }
  
  return(out)
}
if (interactive() && !exists("..sourced_as_library")) {
  # Example usage (只在交互模式下直接运行此文件时执行，source() 时跳过)
  library(GO.db)
  library(AnnotationDbi)
  library(dplyr)

  bp_general_blacklist_auto <- read.csv(
    "/BRC/yan/heart/gtex_GO/bp_general_blacklist_auto.csv",
    header = TRUE
  )$GO.ID

  combined_df_ranked <- annotate_go_with_representative_ancestor(
    df                   = combined_df_filtered,
    go_id_col            = "ID",
    go_name_col          = "Name",
    bp_general_blacklist = bp_general_blacklist_auto,
    add_status           = TRUE
  )
  length(unique(combined_df_ranked$ancestor_TERM_final))
}


