#'Extract RNA sequence from sRNA clusters
#'
#'@description `RNAsequences` extrapolates the RNA sequence for sRNA clusters
#' through two different methods utilising the RNA sequence of the most abundant 
#' transcript identified within each replicate. This can either be determined 
#' by extracting the consensus sequence across replicates or by comparing the
#' sequences across replicates and selecting the most abundant. In this second
#' method ties between sequences can be seen, hence, the user must decide 
#' whether a sequence is then chosen at random from the most abundant or 
#' will exclude any sequence determination. 
#'
#' The function also calculates the RNA & DNA complementary sequences, as well
#' as stating the length/width of the sequence.
#'
#'
#'@param data data.frame; generated by [mobileRNA::RNAimport()]
#'
#'@param original logical; output results to working date as additional
#'columns (`original=TRUE`), or output as new data frame (`original=FALSE`).
#'by default, FALSE
#'
#'@param match.threshold numeric; the minimum number of replicates 
#' required to share the sRNA sequence to count as a match. Default is 1. Only
#' applicable to the "set" method.  
#'
#'@param duplicates character; string to define how to deal with a tie,
#'"random" as default. Options include "random" and "exclude". Only
#' applicable to the "set" method.  
#'
#'
#'@param method character; string to define method. Either "consensus" or "set". 
#'The "consensus" method identifies the consensus sequences across replicated
#'based on the `bioseq` package method. Whereas the "set" is based on the fixed
#'sequences calculated for each replicate and whether they are exact matches or 
#'not. 
#'
#'
#'@param tidy logical; tidy-up data set by removing sRNA clusters with a 
#'unknown or unclassified consensus sRNA sequence result. By default,
#'  \code{tidy=FALSE}, while \code{tidy=TRUE} removes sRNA clusters with 
#' an undetermined consensus RNA sequence. 
#'
#'@details 
#'
#' The set method checks whether each sample in the data set shares
#' the same major sRNA sequence for a given sRNA cluster. If at least two 
#' replicates share the same sRNA sequence, the sequence is pulled and the 
#' complementary DNA and RNA sequences are calculated. Using the 
#' `match.threshold` parameter, we can alter the minimum number of replicates 
#' required to share the RNA sequence to count as a match. For example, if set 
#' as `match.threshold=3`, at least 3 replicates must contain the same sequence. 
#' As a general rule, if only one replicate has determined a sRNA sequence it is 
#' noted that there is no match, but the sequence is pulled and the 
#' complementary sequences calculated.  
#' 
#' The match column can either return "Yes", "No" or "Duplicate". If a match 
#' between replicates is found, "Yes" is supplied, if not, "No". While if 
#' there is a tie between sequences "Duplicate" is supplied. For examples, 
#' if an equal number of replicates have sequence "x" and sequence "y". 
#' 
#' In the situation where duplicates are identified, as default, at random
#' a consensus sRNA sequence is selected. This parameter can be changed to 
#' "exclude", and under this parameter no consensus sequence is pulled. 
#' 
#' Whereas with the consensus method, the consensus sequence is pulled from 
#' all replicates. 
#' 
#'@return The results can be added as additional columns to the working 
#'data frame supplied to the function or stored as a new data frame containing 
#'only the results from the function. The results includes:
#' 
#' - Match: whether the RNA sequence is consistent across replicates
#' - Sequence:  character; sequence of the most abundant sRNA within a cluster
#' - Complementary_RNA: character; complementary RNA nucleotide sequence
#' - Complementary_DNA: character; complementary DNA nucleotide sequence
#' - Width: numeric; length of nucleotide sequence
#'
#'
#'
#'@examples
#'
#'data("sRNA_data")
#'
#' # vector of control names
#' controls <- c("selfgraft_1", "selfgraft_2" , "selfgraft_3")
#'
#' # Locate potentially mobile sRNA clusters associated to tomato, no
#' # statistical analysis
#' sRNA_data_mobile <- RNAmobile(input = "sRNA", data =  sRNA_data,
#' controls = controls, genome.ID = "B_", task = "keep", statistical = FALSE)
#'
#'
#'mobile_sequences <- RNAsequences(sRNA_data_mobile, method = "consensus") 
#'
#'@importFrom dplyr select
#'@importFrom dplyr starts_with
#'@importFrom dplyr where
#'@importFrom dplyr mutate
#'@importFrom bioseq rna
#'@importFrom bioseq seq_consensus
#'@export
RNAsequences <- function(data, original = FALSE, method = c("consensus", "set"),
                         match.threshold = 1, 
                         duplicates  = "random", 
                         tidy = FALSE){
  if (base::missing(data)) {
    stop("data is missing. data must be an object of class matrix, data.frame, 
          DataFrame")
  }
  if (base::missing(method) || !method %in% c("consensus", "set")) {
    stop("Please specify the method parameter, must be either `consensus` or`set`. ")
  }
  df <- data %>% # select only columns with RNA seqs, remove columns with only NA values
    dplyr::select(dplyr::starts_with("MajorRNA")) %>%
    dplyr::select(-dplyr::where(~all(. == "N")))
    if(method == "set"){
      message("The minimum number of matches required to form a consensus sRNA sequence is... ", match.threshold)
      
      if(duplicates == "random"){
        message("---Tie method: random")
      } else 
        if(duplicates == "exclude"){
          message("---Tie method: exclude") 
        }
      match_res <- vector("character", nrow(df))  # Initialize result vector
      sequence_res <- vector("character", nrow(df))
      width_res <- vector("character", nrow(df))
      for (i in seq_len(nrow(df))) {
        row_values <- df[i, ]
        row_sequence <- row_values[row_values != "N"]
        any_match <- any(duplicated(row_sequence))
        if (length(row_sequence) == 0) {
          match <- FALSE # only one "N" elements
          sequence <- NA
        } else 
          if(length(row_sequence) == 1){
            match <- FALSE
            sequence <- row_sequence
          } else
            if(any_match){ # FIND ANY MATCH 
              seq_table <- table(row_sequence) # check how many matches 
              max_value <- max(seq_table)
              # Check if the maximum value is duplicated
              if (!is.na(seq_table[max_value]) && seq_table[max_value] > 1) {
                #if there is duplicate sets of matches 
                # 1 pick at random:
                if(duplicates == "random"){
                  match <- "Duplicate"
                  sequence <- sample(row_sequence, 1)
                } else 
                  if (duplicates == "exclude"){
                    match <- "Duplicate"
                    sequence <- NA
                  }
              } else 
                # match threshold
                if(max(max_value) >= match.threshold){
                  match <- "Yes"
                  sequence <- names(seq_table)[which.max(seq_table)]
                } else 
                  if( (max(max_value) >= match.threshold) == FALSE){
                    match <- "No"
                    sequence <- NA
                  }
            }
        else 
          if(any_match == FALSE){
            match <- "No"
            sequence <- NA
          }
        match_res[i] <- match
        sequence_res[i] <- sequence
        width_res[i] <- nchar(sequence)
      }
      # add column to df
      df$Match <- match_res
      df$Sequence <- sequence_res
      df$Width <- width_res
      # calculate complementary sequences
        df$Complementary_RNA <- vapply(df$Sequence, find_complementary_sequenceRNA, character(1))
        df$Complementary_DNA <- vapply(df$Sequence, find_complementary_sequenceDNA, character(1)) 

      # add as col
      Cluster <-  data[,c(1,5)]
      df <- cbind(Cluster, df )
      # add columns to og data
      if (original){
        data_output <- data %>%
          dplyr::mutate(Match = df$Match,
                        Sequence = df$Sequence,
                        Width = df$Width,
                        Complementary_RNA = df$Complementary_RNA,
                        Complementary_DNA = df$Complementary_DNA)
      } else # made new df
        if(original == FALSE){
          data_output <- df %>%
            dplyr::select(!dplyr::starts_with("MajorRNA"))
        }
      if(tidy){
        message("---Removing sRNA clusters with no consensus sRNA sequence")
        data_output <-  data_output %>%  dplyr::filter(Sequence != "NA")
      }
    }
   if(method == "consensus"){
     # Assuming your dataframe is called df and each column contains sequences
     consensus_sequences <- apply(df, 1, function(row) {
       # Convert the row to a bioseq object
       row_sequences <- bioseq::rna(row)
       # Find the consensus sequence for the row
       consensus_seq <- bioseq::seq_consensus(row_sequences)
       return(consensus_seq)
     })
     consensus_seq_df <- data.frame(Locus = data$Locus, 
                                    Cluster = data$Cluster, 
                                      Sequence = as.vector(consensus_sequences))
     consensus_seq_df$Width <- nchar(consensus_seq_df$Sequence)
     consensus_seq_df$Complementary_RNA <- vapply(consensus_seq_df$Sequence, find_complementary_sequenceRNA, character(1))
     consensus_seq_df$Complementary_DNA <- vapply(consensus_seq_df$Sequence, find_complementary_sequenceDNA, character(1)) 
     
  
     
     # add columns to og data
     if (original){
       data_output <- data %>%
         dplyr::mutate(Sequence = consensus_seq_df$Sequence,
                       Width = consensus_seq_df$Width,
                       Complementary_RNA = consensus_seq_df$Complementary_RNA,
                       Complementary_DNA = consensus_seq_df$Complementary_DNA)
     } else # made new df
       if(original == FALSE){
         data_output <- consensus_seq_df
       }
     
     if(tidy){
       message("---Removing sRNA clusters with no consensus sRNA sequence")
       data_output <- data_output[!grepl("[^AGCU]", data_output$Sequence), ]
     }
   }
 
  return(data_output)
}
