library(GenomicFeatures)

compute_shortest_directional_distance <- function(x, y) {
  
  # Compute the shortest directional distance of items in x from y
  # unlike the GenomicFeatures::distancetoNearest, the distances have a sign
  # where negative: upstream, positive: downstream
  # x and y should be GRanges
  # Returns a dataframe
  
  df_comparison <- tibble(id = x$id)
  
  #####
  # closest distance to y, including the case where the SV intersects the start of a gene
  nearest_any_gene_idx <- nearest(x, y, ignore.strand = FALSE)
  
  idx_query_not_na <- seq(nearest_any_gene_idx)[!is.na(nearest_any_gene_idx)]
  idx_subject_not_na <- nearest_any_gene_idx[!is.na(nearest_any_gene_idx)]
  
  df_comparison$any_Distance <- NA
  df_comparison$any_Distance[idx_query_not_na] <- distance(x[idx_query_not_na], y[idx_subject_not_na])
  df_comparison$any_Gene <- NA
  df_comparison$any_Gene[idx_query_not_na] <- y[idx_subject_not_na]$gene_id
  
  #####
  # precede: get the distance to y which the x is upstream of
  nearest_up_gene_idx <- precede(x, y, ignore.strand=FALSE)
  
  idx_query_not_na <- seq(nearest_up_gene_idx)[!is.na(nearest_up_gene_idx)]
  idx_subject_not_na <- nearest_up_gene_idx[!is.na(nearest_up_gene_idx)]
  
  df_comparison$up_Distance <- NA
  df_comparison$up_Distance[idx_query_not_na] <- distance(x[idx_query_not_na], y[idx_subject_not_na])
  df_comparison$up_Gene <- NA
  df_comparison$up_Gene[idx_query_not_na] <- y[idx_subject_not_na]$gene_id
  
  #####
  # follow: get the distance to y which the x is downstream of
  nearest_down_gene_idx <- follow(x, y, ignore.strand=FALSE)
  
  idx_query_not_na <- seq(nearest_down_gene_idx)[!is.na(nearest_down_gene_idx)]
  idx_subject_not_na <- nearest_down_gene_idx[!is.na(nearest_down_gene_idx)]
  
  df_comparison$down_Distance <- NA
  df_comparison$down_Distance[idx_query_not_na] <- distance(x[idx_query_not_na], y[idx_subject_not_na])
  df_comparison$down_Gene <- NA
  df_comparison$down_Gene[idx_query_not_na] <- y[idx_subject_not_na]$gene_id
  
  #####
  # retrives the shortest absolute distance between these three
  df_summary <- df_comparison %>% 
    pivot_longer(cols = ends_with(c('_Distance', '_Gene')),
                 names_to = c('type', '.value'),
                 names_pattern = "(.*)_(.*)") %>% 
    filter(xor(Distance != 0, type == 'any' ) ) %>%  # only interested in any if it is equal to 0
    group_by(id) %>% 
    summarise(
      distance = min(Distance),
      type = type[which.min(Distance)],
      gene = Gene[which.min(Distance)]  ) %>% 
    mutate(distance = if_else(type == 'up', -distance, distance)) %>% 
    dplyr::select(id, distance, gene)
  
  return(df_summary)
}
