#' @importFrom utils head
#' @method print comparison_vectors
#' @exportS3Method
print.comparison_vectors <- function(x, ...) {

  cat("Comparison based on the following variables: ", paste(x$variables, collapse = ", "), ".\n", sep = "")
  if (!("match" %in% colnames(x$Omega))) {
    cat("True matches are unknown.\n")
  }
  cat("========================================================\n")
  print(head(x$Omega))

}

#' @importFrom utils head
#' @method print rec_lin_model
#' @exportS3Method
print.rec_lin_model <- function(x, ...) {

  cat("Record linkage model based on the following variables: ", paste(x$variables, collapse = ", "), ".\n", sep = "")

  if (!is.null(x$ml_model)) {
    cat("A custom ML model was used.\n")
  }

  cat("The prior probability of matching is ", x$pi_est, ".\n", sep = "")

  if (!is.null(x$b_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the binary method: ", paste(substring(x$b_vars, 7), collapse = ", "), ".\n", sep = "")
    cat("Estimated parameters for the binary method:\n")
    print(x$b_params)
  }

  if (!is.null(x$cpar_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the continuous parametric method: ", paste(substring(x$cpar_vars, 7), collapse = ", "), ".\n", sep = "")
    cat("Estimated parameters for the continuous parametric method:\n")
    print(x$cpar_params)
  }

  if (!is.null(x$cnonpar_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the continuous nonparametric method: ", paste(substring(x$cnonpar_vars, 7), collapse = ", "), ".\n", sep = "")
  }

  cat("========================================================\n")
  cat("Probability/density ratio type: ", x$prob_ratio, ".\n", sep = "")

}

# Keep printed evaluation errors on the same percentage scale as estimated rates.
format_linkage_error_rates <- function(x) {
  formatted_rates <- sprintf("%.4f", x * 100)
  names(formatted_rates) <- paste0(names(x), " (%)")
  noquote(formatted_rates)
}

#' @import data.table
#' @importFrom utils head
#' @method print rec_lin_predictions
#' @exportS3Method
print.rec_lin_predictions <- function(x, ...) {

  if (NROW(x$M_est) == 0) {
    cat("No matches were predicted.\n")
  } else {
    M_est <- data.table::copy(x$M_est)
    data.table::set(M_est, j = "ratio / 1000", value = M_est[["ratio"]] / 1000)
    data.table::set(M_est, j = "ratio", value = NULL)
    M_est_head <- head(M_est, 6)
    cat("The algorithm predicted", NROW(M_est), "matches.\n")
    cat("The first", NROW(M_est_head), "predicted matches are:\n")
    print(M_est_head)
    cat("========================================================\n")
    if (x$set_construction == "size") {
      cat("The construction of the classification set was based on estimates of its size.\n")
    } else if (x$set_construction == "flr") {
      cat("The construction of the classification set was based on the target false link rate (FLR).\n")
      cat("The bisection procedure ended after", x$iter, "iterations.\n")
    } else if (x$set_construction == "mmr") {
      cat("The construction of the classification set was based on the target missing match rate (MMR).\n")
      cat("The bisection procedure ended after", x$iter, "iterations.\n")
    }
    cat("Estimated false link rate (FLR): ", sprintf("%.4f", x$flr_est * 100), " %.\n", sep = "")
    if (x$n_M_est != 0) {
      cat("Estimated missing match rate (MMR): ", sprintf("%.4f", x$mmr_est * 100), " %.\n", sep = "")
    } else {
      cat("Missing match rate (MMR) cannot be estimated because the estimated classification set size is equal to 0.")
    }
  }

  if (!is.null(x$eval_metrics)) {
    cat("========================================================\n")
    cat("Evaluation metrics:\n")
    print(format_linkage_error_rates(x$eval_metrics))
  }

}

#' @import data.table
#' @importFrom utils head
#' @method print mec_rec_lin
#' @exportS3Method
print.mec_rec_lin <- function(x, ...) {

  cat("Record linkage based on the following variables: ", paste(x$variables, collapse = ", "), ".\n", sep = "")
  cat("========================================================\n")
  if (NROW(x$M_est) == 0) {
    cat("No matches were predicted.\n")
  } else {
    M_est <- data.table::copy(x$M_est)
    data.table::set(M_est, j = "ratio / 1000", value = M_est[["ratio"]] / 1000)
    data.table::set(M_est, j = "ratio", value = NULL)
    M_est_head <- head(M_est, 6)
    cat("The algorithm predicted", NROW(M_est), "matches.\n")
    cat("The first", NROW(M_est_head), "predicted matches are:\n")
    print(M_est_head)
    cat("========================================================\n")
  }
  if (x$set_construction == "size") {
    cat("The construction of the classification set was based on estimates of its size.\n")
  } else if (x$set_construction == "flr") {
    cat("The construction of the classification set was based on the target false link rate (FLR).\n")
    cat("The bisection procedure ended after", x$iter_bisection, "iterations.\n")
  } else if (x$set_construction == "mmr") {
    cat("The construction of the classification set was based on the target missing match rate (MMR).\n")
    cat("The bisection procedure ended after", x$iter_bisection, "iterations.\n")
  }
  cat("Estimated false link rate (FLR): ", sprintf("%.4f", x$flr_est * 100), " %.\n", sep = "")
  if (!is.null(x$mmr_est)) {
    cat("Estimated missing match rate (MMR): ", sprintf("%.4f", x$mmr_est * 100), " %.\n", sep = "")
  }

  if (!is.null(x$b_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the binary method: ", paste(substring(x$b_vars, 7), collapse = ", "), ".\n", sep = "")
    cat("Estimated parameters for the binary method:\n")
    print(x$b_params)
  }

  if (!is.null(x$cpar_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the continuous parametric method: ", paste(substring(x$cpar_vars, 7), collapse = ", "), ".\n", sep = "")
    cat("Estimated parameters for the continuous parametric method:\n")
    print(x$cpar_params)
  }

  if (!is.null(x$cnonpar_vars)) {
    cat("========================================================\n")
    cat("Variables selected for the continuous nonparametric method: ", paste(substring(x$cnonpar_vars, 7), collapse = ", "), ".\n", sep = "")
  }

  if (!is.null(x$hm_params)) {
    cat("========================================================\n")
    cat("Variables selected for the hit-miss method: ", paste(substring(x$hm_vars, 7), collapse = ", "), ".\n", sep = "")
    cat("Estimated parameters for the hit-miss method:\n")
    print(x$hm_params)
  }

  if (!is.null(x$eval_metrics)) {
    cat("========================================================\n")
    cat("Evaluation metrics:\n")
    print(format_linkage_error_rates(x$eval_metrics))
  }

}

#' @import data.table
#' @importFrom utils head
#' @method print mec_blocking
#' @exportS3Method
print.mec_blocking <- function(x, ...) {

  cat("Blocked MEC record linkage based on: ", "\n")
  cat(paste(x$variables, collapse = ", "), ".\n", sep = "")
  cat("========================================================\n")

  if (NROW(x$M_est) == 0) {
    cat("No matches were predicted.\n")
  } else {
    M_est <- data.table::copy(x$M_est)
    data.table::set(M_est, j = "ratio / 1000", value = M_est[["ratio"]] / 1000)
    data.table::set(M_est, j = "ratio", value = NULL)
    M_est_head <- head(M_est, 6)
    cat("The algorithm predicted", NROW(M_est), "matches.\n")
    cat("The first", NROW(M_est_head), "predicted matches are:\n")
    print(M_est_head)
    cat("========================================================\n")
  }

  if (!is.null(x$blocking_eval)) {
    cat("========================================================\n")
    cat("Blocking diagnostics:\n")
    cat("Known matches: ", x$blocking_eval[["true_matches"]], ".\n", sep = "")
    cat("Known matches retained by blocking: ", x$blocking_eval[["preserved_matches"]], ".\n", sep = "")
    cat("Known matches missed by blocking: ", x$blocking_eval[["lost_matches"]], ".\n", sep = "")
    cat("Blocking MMR: ", sprintf("%.4f", x$blocking_eval[["blocking_fnr"]] * 100), " %.\n", sep = "")
    cat("Candidate pairs retained: ", x$blocking_eval[["blocked_pairs"]],
        " of ", x$blocking_eval[["full_pairs"]], ".\n", sep = "")
    pair_reduction <- 1 - x$blocking_eval[["blocked_pairs"]] / x$blocking_eval[["full_pairs"]]
    cat("Candidate pair reduction: ", sprintf("%.4f", pair_reduction * 100), " %.\n", sep = "")
  }

  if (!is.null(x$eval_metrics)) {
    cat("========================================================\n")
    cat("Evaluation metrics:\n")
    print(format_linkage_error_rates(x$eval_metrics))
  }

}
