"look_up" <- function(x, dic, lang = "sumer", width = 70, mapping = NULL) {

  if (is.null(mapping)) {
    path    <- system.file("extdata", "etcsl_mapping.txt", package = "sumer")
    mapping <- read.csv2(path, sep = ";", na.strings = "")
  }

  # Hilfsfunktion: Art der Eingabe feststellen

  is_sumerian <- function(x) {
    x <- str_replace_all(x, "[()\\[\\]{}\\.,\\-<>\u00a4\u2218]", " ")
    x <- str_squish(x)
    x <- str_replace_all(x, " ", "-")
    x <- str_split_1(x, "-")[1]

    lowercase <- "[a-z\u011d\u0161\u1e2b\u00e1\u00e9\u00ed\u00fa\u00e0\u00e8\u00ec\u00f9]+[0-9]*"
    uppercase <- "[A-Z\u0160\u011c\u1e2a](?:[A-Z\u0160\u011c\u1e2a0-9\u00d7+/%\u00b7]|gunu|tenu|\u0161e\u0161ig)*"
    cuneiform <- "[\\x{12000}-\\x{12500}\u2205]"
    others    <- paste0("<", lowercase, ">|<", uppercase, ">|", uppercase)

    result <- str_detect(str_sub(x, 1, 1), cuneiform) || str_detect(x, paste0("^(", others, ")$"))

    return(result)
  }

  if (is_sumerian(x) && lang != "sumer" && lang != "sum") {
    lang <- "sumer"
    warning("The language was changed to 'sumer'.")
  }

  # Ergebnisobjekt initialisieren
  result <- list(
    search       = x,
    lang         = lang,
    width        = width,
    mapping      = mapping,
    cuneiform    = NULL,
    sign_name    = NULL,
    translations = NULL,
    substrings   = NULL,
    matches      = NULL
  )

  if (lang == "sumer" || lang == "sum") {
    flat.x <- str_replace_all(x, "[()\\[\\]{}\\.,\\-<>\u00a4\u2218]", " ")
    flat.x <- str_squish(flat.x)
    flat.x <- str_replace_all(flat.x, " ", "-")

    result$cuneiform <- as.cuneiform(flat.x, mapping = mapping)
    result$sign_name <- as.sign_name(flat.x, mapping = mapping)

    # Haupteinträge
    name <- result$sign_name
    result$translations <- dic[(dic$sign_name == name) & (dic$row_type == "trans."), ]

    # Teil-Zeichenketten
    words <- str_split_1(name, "\\.")
    n <- length(words)
    substrings <- unlist(lapply(1:n, function(i) {
      sapply(i:n, function(j) str_c(words[i:j], collapse = "."))
    }))
    substrings <- substrings[substrings != name]
    substrings <- substrings[substrings %in% dic$sign_name]

    if (length(substrings) > 0) {
      result$substrings <- lapply(substrings, function(s) {
        dic[(dic$sign_name == s) & (dic$row_type == "trans."), ]
      })
      names(result$substrings) <- substrings
    }

  } else {
    # Suche nach deutschem/englischem Begriff
    pattern <- paste0("(?<!\\p{L})", str_escape(x), "(?!\\p{L})")
    use     <- str_detect(dic$meaning, regex(pattern, ignore_case = TRUE)) & (dic$row_type == "trans.")
    result$matches <- dic[use, ]
  }

  class(result) <- "look_up"
  return(result)
}


"print.look_up" <- function(x, ...) {


  width <- x$width

  # Hilfsfunktion: Text auf feste Breite auffüllen (Unicode-sicher)
  pad_right <- function(text, width) {
    n <- nchar(text)
    if (n < width) {
      paste0(text, paste(rep(" ", width - n), collapse = ""))
    } else {
      text
    }
  }

  # Hilfsfunktion für blauen Text
  blue <- function(text) {
    cli::col_blue(text)
  }

  # Hilfsfunktion: Suchbegriff im Text hervorheben
  highlight <- function(text, pattern) {
    str_replace_all(
      text,
      regex(paste0("((?<!\\p{L})", str_escape(pattern), "(?!\\p{L}))"), ignore_case = TRUE),
      blue("\\1")
    )
  }

  # Hilfsfunktion: Text umbrechen
  wrap_text <- function(text, width, indent = 10) {
    indent_str <- paste(rep(" ", indent), collapse = "")
    lines <- strwrap(text, width = width)
    paste(lines, collapse = paste0("\n", indent_str))
  }

  # Hilfsfunktion: Einträge formatiert ausgeben (kompakt, für kurze sign_names)
  print_entries_compact <- function(df) {
    if (nrow(df) == 0) {
      cat("  (no entries found)\n")
      return(invisible(NULL))
    }
    for (i in 1:nrow(df)) {
      count_str <- if (is.na(df$count[i])) " " else sprintf("%2d", df$count[i])
      type_str  <- pad_right(df$type[i], 6)
      meaning   <- wrap_text(df$meaning[i], width, indent = 14)
      cat(sprintf("  [%s] %s %s\n", count_str, type_str, meaning))
    }
  }

  # Hilfsfunktion: Einträge formatiert ausgeben (mehrzeilig, für lange sign_names)
  print_entries_full <- function(df, pattern, show_cuneiform = FALSE) {
    if (nrow(df) == 0) {
      cat("  (no entries found)\n")
      return(invisible(NULL))
    }
    for (i in 1:nrow(df)) {
      # Zeile 1: sign_name (und optional Keilschrift)
      if (show_cuneiform) {
        cune <- as.cuneiform(df$sign_name[i], mapping = x$mapping)
        cat(sprintf("\n  %s  %s\n", df$sign_name[i], cune))
      } else {
        cat(sprintf("\n  %s\n", df$sign_name[i]))
      }
      # Zeile 2+: count, type, meaning
      count_str <- if (is.na(df$count[i])) " " else sprintf("%d", df$count[i])
      type_str  <- pad_right(df$type[i], 6)
      meaning   <- highlight(df$meaning[i], pattern)
      meaning   <- wrap_text(meaning, width, indent = 13)

      cat(sprintf("  [%s] %-6s %s\n", count_str, type_str, meaning))
    }
  }

  # Trennlinie
  line <- paste(rep("\u2500", width + 20), collapse = "")

  cat("\n", line, "\n", sep = "")
  cat(" Search: ", x$search, "\n", sep = "")
  cat(line, "\n", sep = "")

  if (x$lang == "sumer" || x$lang == "sum") {

    cat("\n Cuneiform:   ", x$cuneiform, "\n", sep = "")
    cat(" Sign Names:  ", x$sign_name, "\n\n", sep = "")

    # Haupteintrag
    cat(" \u25b6 Translations:\n")
    print_entries_compact(x$translations)

    # Teil-Zeichenketten
    if (!is.null(x$substrings) && length(x$substrings) > 0) {
      cat("\n \u25b6 Individual Signs / Substrings:\n")
      for (s in names(x$substrings)) {
        sub_df <- x$substrings[[s]]
        cune_s <- as.cuneiform(s, mapping = x$mapping)
        cat(sprintf("\n  %s  %s\n", s, cune_s))
        for (j in 1:nrow(sub_df)) {
          count_str <- if (is.na(sub_df$count[j])) " " else pad_right(paste0("[", sub_df$count[j], "]"), 4)
          type_str  <- pad_right(sub_df$type[j], 6)
          meaning   <- wrap_text(sub_df$meaning[j], width, indent = 14)
          cat(sprintf("  %s %-6s %s\n", count_str, type_str, meaning))
        }
      }
    }

  } else {
    # Suche nach deutschem/englischem Begriff
    cat("\n \u25b6 Matches for '", x$search, "':\n", sep = "")
    print_entries_full(x$matches, x$search, show_cuneiform = TRUE)
  }

  cat("\n", line, "\n\n", sep = "")
  invisible(x)
}
