code: def _fix_encoding_one_step_and_explain(
      text: str, config: TextFixerConfig
  ) -> ExplainedText:
      """
      Perform one step of fixing the encoding of text.
      """
      if config is None:
          config = TextFixerConfig()
  
      if len(text) == 0:
          return ExplainedText(text, [])
  
      # The first plan is to return ASCII text unchanged, as well as text
      # that doesn't look like it contains mojibake
      if chardata.possible_encoding(text, "ascii") or not is_bad(text):
          return ExplainedText(text, [])
  
      # As we go through the next step, remember the possible encodings
      # that we encounter but don't successfully fix yet. We may need them
      # later.
      possible_1byte_encodings = []
  
      # Suppose the text was supposed to be UTF-8, but it was decoded using
      # a single-byte encoding instead. When these cases can be fixed, they
      # are usually the correct thing to do, so try them next.
      for encoding in chardata.CHARMAP_ENCODINGS:
          if chardata.possible_encoding(text, encoding):
              possible_1byte_encodings.append(encoding)
              encoded_bytes = text.encode(encoding)
              encode_step = ExplanationStep("encode", encoding)
              transcode_steps = []
  
              # Now, find out if it's UTF-8 (or close enough). Otherwise,
              # remember the encoding for later.
              try:
                  decoding = "utf-8"
                  # Check encoded_bytes for sequences that would be UTF-8,
                  # except they have b' ' where b'\xa0' would belong.
                  if (
                      config.restore_byte_a0
                      and chardata.ALTERED_UTF8_RE.search(encoded_bytes)
                  ):
                      replaced_bytes = fixes.restore_byte_a0(
                          encoded_bytes
                      )
                      if replaced_bytes != encoded_bytes:
                          transcode_steps.append(
                              ExplanationStep(
                                  "transcode", "restore_byte_a0"
                              )
                          )
                          encoded_bytes = replaced_bytes
  
                  # Replace sequences where information has been lost
                  if (
                      config.replace_lossy_sequences
                      and encoding.startswith("sloppy")
                  ):
                      replaced_bytes = fixes.replace_lossy_sequences(
                          encoded_bytes
                      )
                      if replaced_bytes != encoded_bytes:
                          transcode_steps.append(
                              ExplanationStep(
                                  "transcode", "replace_lossy_sequences"
                              )
                          )
                          encoded_bytes = replaced_bytes
  
                  if 0xED in encoded_bytes or 0xC0 in encoded_bytes:
                      decoding = "utf-8-variants"
  
                  decode_step = ExplanationStep("decode", decoding)
                  steps = (
                      [encode_step] + transcode_steps + [decode_step]
                  )
                  fixed = encoded_bytes.decode(decoding)
                  return ExplainedText(fixed, steps)
  
              except UnicodeDecodeError:
                  pass
  
      # Look for a-hat-euro sequences that remain, and fix them in isolation.
      if (
          config.decode_inconsistent_utf8
          and chardata.UTF8_DETECTOR_RE.search(text)
      ):
          steps = [ExplanationStep("apply", "decode_inconsistent_utf8")]
          fixed = fixes.decode_inconsistent_utf8(text)
          if fixed != text:
              return ExplainedText(fixed, steps)
  
      # The next most likely case is that this is Latin-1 that was intended to
      # be read as Windows-1252, because those two encodings in particular are
      # easily confused.
      if "latin-1" in possible_1byte_encodings:
          if "windows-1252" in possible_1byte_encodings:
              # This text is in the intersection of Latin-1 and
              # Windows-1252, so it's probably legit.
              return ExplainedText(text, [])
          else:
              # Otherwise, it means we have characters that are in Latin-1 but
              # not in Windows-1252. Those are C1 control characters. Nobody
              # wants those. Assume they were meant to be Windows-1252.
              try:
                  fixed = text.encode("latin-1").decode("windows-1252")
                  if fixed != text:
                      steps = [
                          ExplanationStep("encode", "latin-1"),
                          ExplanationStep("decode", "windows-1252"),
                      ]
                      return ExplainedText(fixed, steps)
              except UnicodeDecodeError:
                  pass
  
      # Fix individual characters of Latin-1 with a less satisfying explanation
      if config.fix_c1_controls and chardata.C1_CONTROL_RE.search(text):
          steps = [ExplanationStep("transcode", "fix_c1_controls")]
          fixed = fixes.fix_c1_controls(text)
          return ExplainedText(fixed, steps)
  
      # The cases that remain are mixups between two different single-byte
      # encodings, and not the common case of Latin-1 vs. Windows-1252.
      #
      # With the new heuristic in 6.0, it's possible that we're closer to solving
      # these in some cases. It would require a lot of testing and tuning, though.
      # For now, we leave the text unchanged in these cases.
      return ExplainedText(text, [])
  
imports: from __future__ import annotations
  import unicodedata
  import warnings
  from typing import Any, BinaryIO, Dict, Iterator, List, NamedTuple, Optional, TextIO, Tuple, Union, cast, no_type_check
  from ftfy import bad_codecs
  from ftfy import chardata, fixes
  from ftfy.badness import is_bad
  from ftfy.formatting import display_ljust
label_desc: Use image node_id 6 for calling a global function with example usage: _fix_encoding_one_step_and_explain(text, config) and returns: ExplainedText, ExplainedText, ExplainedText, ExplainedText, ExplainedText, ExplainedText, ExplainedText, ExplainedText