// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

use {
  crate::{
    styles::Styles,
    writer::Writer,
  },
  owo_colors::OwoColorize,
  std::{
    cell::{
      RefCell,
      RefMut,
    },
    fmt::Write,
    rc::Rc,
    sync::Arc,
  },
  unicode_width::UnicodeWidthStr,
};

macro_rules! prefix_chars {
  ($($dbgid:ident : $name:ident -> $value:expr $( => $color:expr)? ),* $(,)?) => {
    paste::paste! {
      #[derive(Clone, PartialEq, Eq,)]
      pub(crate) enum Glyph {
        $($name),*
      }

      impl std::fmt::Display for Glyph {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
          match self {
          $(
            | Glyph::$name => write!(f, "{}", $value),
          )*
          }
        }
      }

      impl std::fmt::Debug for Glyph {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
          match self {
          $(
            | Glyph::$name => write!(f, "{:}", stringify!($dbgid)),
          )*
          }
        }
      }

      impl<'a> Prefix<'a> {
        $(
          pub fn [<write_glyph_ $name:snake>](&self, w: &mut Writer, style: &'a Styles
          ) -> std::fmt::Result {
            w.write_prefix(format!("{}", $value))
          }
        )*
      }
    }
  };
}

// ┏━━━━━━━━┳━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┯━━━┓
// ┃        ┃ 0 │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ A │ B │ C │ D │ E │ F ┃
// ┣━━━━━━━━╋━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┿━━━┫
// ┃ U+250x ┃ ─ │ ━ │ │ │ ┃ │ ┄ │ ┅ │ ┆ │ ┇ │ ┈ │ ┉ │ ┊ │ ┋ │ ┌ │ ┍ │ ┎ │ ┏ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+251x ┃ ┐ │ ┑ │ ┒ │ ┓ │ └ │ ┕ │ ┖ │ ┗ │ ┘ │ ┙ │ ┚ │ ┛ │ ├ │ ┝ │ ┞ │ ┟ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+252x ┃ ┠ │ ┡ │ ┢ │ ┣ │ ┤ │ ┥ │ ┦ │ ┧ │ ┨ │ ┩ │ ┪ │ ┫ │ ┬ │ ┭ │ ┮ │ ┯ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+253x ┃ ┰ │ ┱ │ ┲ │ ┳ │ ┴ │ ┵ │ ┶ │ ┷ │ ┸ │ ┹ │ ┺ │ ┻ │ ┼ │ ┽ │ ┾ │ ┿ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+254x ┃ ╀ │ ╁ │ ╂ │ ╃ │ ╄ │ ╅ │ ╆ │ ╇ │ ╈ │ ╉ │ ╊ │ ╋ │ ╌ │ ╍ │ ╎ │ ╏ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+255x ┃ ═ │ ║ │ ╒ │ ╓ │ ╔ │ ╕ │ ╖ │ ╗ │ ╘ │ ╙ │ ╚ │ ╛ │ ╜ │ ╝ │ ╞ │ ╟ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+256x ┃ ╠ │ ╡ │ ╢ │ ╣ │ ╤ │ ╥ │ ╦ │ ╧ │ ╨ │ ╩ │ ╪ │ ╫ │ ╬ │ ╭ │ ╮ │ ╯ ┃
// ┠────────╂───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┨
// ┃ U+257x ┃ ╰ │ ╱ │ ╲ │ ╳ │ ╴ │ ╵ │ ╶ │ ╷ │ ╸ │ ╹ │ ╺ │ ╻ │ ╼ │ ╽ │ ╾ │ ╿ ┃
// ┗━━━━━━━━┻━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┷━━━┛

prefix_chars! {
  BNK: Blank -> ' ',
  // VRT: Vertical -> '│',
  // HVT: HeavyVertical -> '┃',
  // HCN: HorizontalConnection -> '┬',
  // LCN: LastConnection -> '└',
  DBG: Debug -> '⏺',
  DB2: Debug2 -> '○',
  RUT: Root -> '◈',

  N__: NodeCollapse -> "",
  NC_: NodeNodesCollapse -> "",
  _C_: NodesCollapse -> "",
  R__: RootCollapse -> "",
  __F: FieldCollapse -> "",
  __L: LeafCollapse -> "",

  CHD: DebugNodes -> 'C',
  NDE: DebugNode -> 'N',
  NCD: DebugNodeNodes -> 'M',
  FLD: DebugField -> 'F',
  LAF: DebugLeaf -> 'L',

  // RMV is a special case, it's means to remove the previous glpyh
  RMV: Remove -> "",

  DSH: Dash -> '·',

  // Box drawing chars
  // U+2500: LIGHT HORIZONTAL
  LH: LightHorizontal -> '─',
  // U+2501: HEAVY HORIZONTAL
  HH: HeavyHorizontal -> '━',
  // U+2502: LIGHT VERTICAL
  LV: LightVertical -> '│',
  // U+2503: HEAVY VERTICAL
  HV: HeavyVertical -> '┃',
  // U+2504: LIGHT TRIPLE DASH HORIZONTAL
  LTDH: LightTripleDashHorizontal -> '┄',
  // U+2505: HEAVY TRIPLE DASH HORIZONTAL
  HTDH: HeavyTripleDashHorizontal -> '┅',
  // U+2506: LIGHT TRIPLE DASH VERTICAL
  LTDV: LightTripleDashVertical -> '┆',
  // U+2507: HEAVY TRIPLE DASH VERTICAL
  HTDV: HeavyTripleDashVertical -> '┇',
  // U+2508: LIGHT QUADRUPLE DASH HORIZONTAL
  LQDH: LightQuadrupleDashHorizontal -> '┈',
  // U+2509: HEAVY QUADRUPLE DASH HORIZONTAL
  HQDH: HeavyQuadrupleDashHorizontal -> '┉',
  // U+250A: LIGHT QUADRUPLE DASH VERTICAL
  LQDV: LightQuadrupleDashVertical -> '┊',
  // U+250B: HEAVY QUADRUPLE DASH VERTICAL
  HQDV: HeavyQuadrupleDashVertical -> '┋',
  // U+250C: LIGHT DOWN AND RIGHT
  LD_R: LightDownRight -> '┌',
  // U+250D: DOWN LIGHT AND RIGHT HEAVY
  DL_RH: DownLightRightHeavy -> '┍',
  // U+250E: DOWN HEAVY AND RIGHT LIGHT
  DH_RL: DownHeavyRightLight -> '┎',
  // U+250F: HEAVY DOWN AND RIGHT
  HD_R: HeavyDownRight -> '┏',
  // U+2510: LIGHT DOWN AND LEFT
  LD_L: LightDownLeft -> '┐',
  // U+2511: DOWN LIGHT AND LEFT HEAVY
  DL_LH: DownLightLeftHeavy -> '┑',
  // U+2512: DOWN HEAVY AND LEFT LIGHT
  DH_LL: DownHeavyLeftLight -> '┒',
  // U+2513: HEAVY DOWN AND LEFT
  HD_L: HeavyDownLeft -> '┓',
  // U+2514: LIGHT UP AND RIGHT
  LU_R: LightUpRight -> '└',
  // U+2515: UP LIGHT AND RIGHT HEAVY
  UL_RH: UpLightRightHeavy -> '┕',
  // U+2516: UP HEAVY AND RIGHT LIGHT
  UH_RL: UpHeavyRightLight -> '┖',
  // U+2517: HEAVY UP AND RIGHT
  HU_R: HeavyUpRight -> '┗',
  // U+2518: LIGHT UP AND LEFT
  LU_L: LightUpLeft -> '┘',
  // U+2519: UP LIGHT AND LEFT HEAVY
  UL_LH: UpLightLeftHeavy -> '┙',
  // U+251A: UP HEAVY AND LEFT LIGHT
  UH_LL: UpHeavyLeftLight -> '┚',
  // U+251B: HEAVY UP AND LEFT
  HU_L: HeavyUpLeft -> '┛',
  // U+251C: LIGHT VERTICAL AND RIGHT
  LV_R: LightVerticalRight -> '├',
  // U+251D: VERTICAL LIGHT AND RIGHT HEAVY
  VL_RH: VerticalLightRightHeavy -> '┝',
  // U+251E: UP HEAVY AND RIGHT DOWN LIGHT
  UH_RDL: UpHeavyRightDownLight -> '┞',
  // U+251F: DOWN HEAVY AND RIGHT UP LIGHT
  DH_RUL: DownHeavyRightUpLight -> '┟',
  // U+2520: VERTICAL HEAVY AND RIGHT LIGHT
  VH_RL: VerticalHeavyRightLight -> '┠',
  // U+2521: DOWN LIGHT AND RIGHT UP HEAVY
  DL_RUH: DownLightRightUpHeavy -> '┡',
  // U+2522: UP LIGHT AND RIGHT DOWN HEAVY
  UL_RDH: UpLightRightDownHeavy -> '┢',
  // U+2523: HEAVY VERTICAL AND RIGHT
  HV_R: HeavyVerticalRight -> '┣',
  // U+2524: LIGHT VERTICAL AND LEFT
  LV_L: LightVerticalLeft -> '┤',
  // U+2525: VERTICAL LIGHT AND LEFT HEAVY
  VL_LH: VerticalLightLeftHeavy -> '┥',
  // U+2526: UP HEAVY AND LEFT DOWN LIGHT
  UH_LDL: UpHeavyLeftDownLight -> '┦',
  // U+2527: DOWN HEAVY AND LEFT UP LIGHT
  DH_LUL: DownHeavyLeftUpLight -> '┧',
  // U+2528: VERTICAL HEAVY AND LEFT LIGHT
  VH_LL: VerticalHeavyLeftLight -> '┨',
  // U+2529: DOWN LIGHT AND LEFT UP HEAVY
  DL_LUH: DownLightLeftUpHeavy -> '┩',
  // U+252A: UP LIGHT AND LEFT DOWN HEAVY
  UL_LDH: UpLightLeftDownHeavy -> '┪',
  // U+252B: HEAVY VERTICAL AND LEFT
  HV_L: HeavyVerticalLeft -> '┫',
  // U+252C: LIGHT DOWN AND HORIZONTAL
  LD_H: LightDownHorizontal -> '┬',
  // U+252D: LEFT HEAVY AND RIGHT DOWN LIGHT
  LH_RDL: LeftHeavyRightDownLight -> '┭',
  // U+252E: RIGHT HEAVY AND LEFT DOWN LIGHT
  RH_LDL: RightHeavyLeftDownLight -> '┮',
  // U+252F: DOWN LIGHT AND HORIZONTAL HEAVY
  DL_HH: DownLightHorizontalHeavy -> '┯',
  // U+2530: DOWN HEAVY AND HORIZONTAL LIGHT
  DH_HL: DownHeavyHorizontalLight -> '┰',
  // U+2531: RIGHT LIGHT AND LEFT DOWN HEAVY
  RL_LDH: RightLightLeftDownHeavy -> '┱',
  // U+2532: LEFT LIGHT AND RIGHT DOWN HEAVY
  LL_RDH: LeftLightRightDownHeavy -> '┲',
  // U+2533: HEAVY DOWN AND HORIZONTAL
  HD_H: HeavyDownHorizontal -> '┳',
  // U+2534: LIGHT UP AND HORIZONTAL
  LU_H: LightUpHorizontal -> '┴',
  // U+2535: LEFT HEAVY AND RIGHT UP LIGHT
  LH_RUL: LeftHeavyRightUpLight -> '┵',
  // U+2536: RIGHT HEAVY AND LEFT UP LIGHT
  RH_LUL: RightHeavyLeftUpLight -> '┶',
  // U+2537: UP LIGHT AND HORIZONTAL HEAVY
  UL_HH: UpLightHorizontalHeavy -> '┷',
  // U+2538: UP HEAVY AND HORIZONTAL LIGHT
  UH_HL: UpHeavyHorizontalLight -> '┸',
  // U+2539: RIGHT LIGHT AND LEFT UP HEAVY
  RL_LUH: RightLightLeftUpHeavy -> '┹',
  // U+253A: LEFT LIGHT AND RIGHT UP HEAVY
  LL_RUH: LeftLightRightUpHeavy -> '┺',
  // U+253B: HEAVY UP AND HORIZONTAL
  HU_H: HeavyUpHorizontal -> '┻',
  // U+253C: LIGHT VERTICAL AND HORIZONTAL
  LV_H: LightVerticalHorizontal -> '┼',
  // U+253D: LEFT HEAVY AND RIGHT VERTICAL LIGHT
  LH_RVL: LeftHeavyRightVerticalLight -> '┽',
  // U+253E: RIGHT HEAVY AND LEFT VERTICAL LIGHT
  RH_LVL: RightHeavyLeftVerticalLight -> '┾',
  // U+253F: VERTICAL LIGHT AND HORIZONTAL HEAVY
  VL_HH: VerticalLightHorizontalHeavy -> '┿',
  // U+2540: UP HEAVY AND DOWN HORIZONTAL LIGHT
  UH_DHL: UpHeavyDownHorizontalLight -> '╀',
  // U+2541: DOWN HEAVY AND UP HORIZONTAL LIGHT
  DH_UHL: DownHeavyUpHorizontalLight -> '╁',
  // U+2542: VERTICAL HEAVY AND HORIZONTAL LIGHT
  VH_HL: VerticalHeavyHorizontalLight -> '╂',
  // U+2543: LEFT UP HEAVY AND RIGHT DOWN LIGHT
  LUH_RDL: LeftUpHeavyRightDownLight -> '╃',
  // U+2544: RIGHT UP HEAVY AND LEFT DOWN LIGHT
  RUH_LDL: RightUpHeavyLeftDownLight -> '╄',
  // U+2545: LEFT DOWN HEAVY AND RIGHT UP LIGHT
  LDH_RUL: LeftDownHeavyRightUpLight -> '╅',
  // U+2546: RIGHT DOWN HEAVY AND LEFT UP LIGHT
  RDH_LUL: RightDownHeavyLeftUpLight -> '╆',
  // U+2547: DOWN LIGHT AND UP HORIZONTAL HEAVY
  DL_UHH: DownLightUpHorizontalHeavy -> '╇',
  // U+2548: UP LIGHT AND DOWN HORIZONTAL HEAVY
  UL_DHH: UpLightDownHorizontalHeavy -> '╈',
  // U+2549: RIGHT LIGHT AND LEFT VERTICAL HEAVY
  RL_LVH: RightLightLeftVerticalHeavy -> '╉',
  // U+254A: LEFT LIGHT AND RIGHT VERTICAL HEAVY
  LL_RVH: LeftLightRightVerticalHeavy -> '╊',
  // U+254B: HEAVY VERTICAL AND HORIZONTAL
  HV_H: HeavyVerticalHorizontal -> '╋',
  // U+254C: LIGHT DOUBLE DASH HORIZONTAL
  LDDH: LightDoubleDashHorizontal -> '╌',
  // U+254D: HEAVY DOUBLE DASH HORIZONTAL
  HDDH: HeavyDoubleDashHorizontal -> '╍',
  // U+254E: LIGHT DOUBLE DASH VERTICAL
  LDDV: LightDoubleDashVertical -> '╎',
  // U+254F: HEAVY DOUBLE DASH VERTICAL
  HDDV: HeavyDoubleDashVertical -> '╏',
  // U+2550: DOUBLE HORIZONTAL
  DH: DoubleHorizontal -> '═',
  // U+2551: DOUBLE VERTICAL
  DV: DoubleVertical -> '║',
  // U+2552: DOWN SINGLE AND RIGHT DOUBLE
  DS_RD: DownSingleRightDouble -> '╒',
  // U+2553: DOWN DOUBLE AND RIGHT SINGLE
  DD_RS: DownDoubleRightSingle -> '╓',
  // U+2554: DOUBLE DOWN AND RIGHT
  DD_R: DoubleDownRight -> '╔',
  // U+2555: DOWN SINGLE AND LEFT DOUBLE
  DS_LD: DownSingleLeftDouble -> '╕',
  // U+2556: DOWN DOUBLE AND LEFT SINGLE
  DD_LS: DownDoubleLeftSingle -> '╖',
  // U+2557: DOUBLE DOWN AND LEFT
  DD_L: DoubleDownLeft -> '╗',
  // U+2558: UP SINGLE AND RIGHT DOUBLE
  US_RD: UpSingleRightDouble -> '╘',
  // U+2559: UP DOUBLE AND RIGHT SINGLE
  UD_RS: UpDoubleRightSingle -> '╙',
  // U+255A: DOUBLE UP AND RIGHT
  DU_R: DoubleUpRight -> '╚',
  // U+255B: UP SINGLE AND LEFT DOUBLE
  US_LD: UpSingleLeftDouble -> '╛',
  // U+255C: UP DOUBLE AND LEFT SINGLE
  UD_LS: UpDoubleLeftSingle -> '╜',
  // U+255D: DOUBLE UP AND LEFT
  DU_L: DoubleUpLeft -> '╝',
  // U+255E: VERTICAL SINGLE AND RIGHT DOUBLE
  VS_RD: VerticalSingleRightDouble -> '╞',
  // U+255F: VERTICAL DOUBLE AND RIGHT SINGLE
  VD_RS: VerticalDoubleRightSingle -> '╟',
  // U+2560: DOUBLE VERTICAL AND RIGHT
  DV_R: DoubleVerticalRight -> '╠',
  // U+2561: VERTICAL SINGLE AND LEFT DOUBLE
  VS_LD: VerticalSingleLeftDouble -> '╡',
  // U+2562: VERTICAL DOUBLE AND LEFT SINGLE
  VD_LS: VerticalDoubleLeftSingle -> '╢',
  // U+2563: DOUBLE VERTICAL AND LEFT
  DV_L: DoubleVerticalLeft -> '╣',
  // U+2564: DOWN SINGLE AND HORIZONTAL DOUBLE
  DS_HD: DownSingleHorizontalDouble -> '╤',
  // U+2565: DOWN DOUBLE AND HORIZONTAL SINGLE
  DD_HS: DownDoubleHorizontalSingle -> '╥',
  // U+2566: DOUBLE DOWN AND HORIZONTAL
  DD_H: DoubleDownHorizontal -> '╦',
  // U+2567: UP SINGLE AND HORIZONTAL DOUBLE
  US_HD: UpSingleHorizontalDouble -> '╧',
  // U+2568: UP DOUBLE AND HORIZONTAL SINGLE
  UD_HS: UpDoubleHorizontalSingle -> '╨',
  // U+2569: DOUBLE UP AND HORIZONTAL
  DU_H: DoubleUpHorizontal -> '╩',
  // U+256A: VERTICAL SINGLE AND HORIZONTAL DOUBLE
  VS_HD: VerticalSingleHorizontalDouble -> '╪',
  // U+256B: VERTICAL DOUBLE AND HORIZONTAL SINGLE
  VD_HS: VerticalDoubleHorizontalSingle -> '╫',
  // U+256C: DOUBLE VERTICAL AND HORIZONTAL
  DV_H: DoubleVerticalHorizontal -> '╬',
  // U+256D: LIGHT ARC DOWN AND RIGHT
  LAD_R: LightArcDownRight -> '╭',
  // U+256E: LIGHT ARC DOWN AND LEFT
  LAU_L: LightArcUpLeft -> '╮',
  // U+256F: LIGHT ARC UP AND LEFT
  LAD_L: LightArcDownLeft -> '╯',
  // U+2570: LIGHT ARC UP AND RIGHT
  LDURTLL: LightDiagonalUpperRightToLowerLeft -> '╰',
  // U+2571: LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT
  LAU_R: LightArcUpRight -> '╱',
  // U+2572: LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT
  LDC: LightDiagonalCross -> '╲',
  // U+2573: LIGHT DIAGONAL CROSS
  LDULTLR: LightDiagonalUpperLeftToLowerRight -> '╳',
  // U+2574: LIGHT LEFT
  LU: LightUp -> '╴',
  // U+2575: LIGHT UP
  LL: LightLeft -> '╵',
  // U+2576: LIGHT RIGHT
  LD: LightDown -> '╶',
  // U+2577: LIGHT DOWN
  LR: LightRight -> '╷',
  // U+2578: HEAVY LEFT
  HU: HeavyUp -> '╸',
  // U+2579: HEAVY UP
  HL: HeavyLeft -> '╹',
  // U+257A: HEAVY RIGHT
  HD: HeavyDown -> '╺',
  // U+257B: HEAVY DOWN
  HR: HeavyRight -> '╻',
  // U+257C: LIGHT LEFT AND HEAVY RIGHT
  LU_HD: LightUpHeavyDown -> '╼',
  // U+257D: LIGHT UP AND HEAVY DOWN
  LL_HR: LightLeftHeavyRight -> '╽',
  // U+257E: HEAVY LEFT AND LIGHT RIGHT
  HU_LD: HeavyUpLightDown -> '╾',
  // U+257F: HEAVY UP AND LIGHT DOWN
  HL_LR: HeavyLeftLightRight -> '╿',
}

#[derive(Clone)]
pub(crate) enum Stack {
  Root,
  BlankLine,
  Divider,

  Node {
    has_fields: bool,
    last_node:  bool,
  },
  Leaf {
    has_fields: bool,
    last_node:  bool,
  },
  LeafField {
    last_node:   bool,
    first_field: bool,
    last_field:  bool,
  },
  NodeField {
    last_node:   bool,
    first_field: bool,
    last_field:  bool,
  },
  Nodes {
    first_node: bool,
    last_node:  bool,
    has_nodes:  bool,
  },
}

fn format_flag(label: &str, active: &bool) -> String {
  match *active {
    | true => {
      format!("{sep}{}", label.bright_white(), sep = ":".dimmed())
    },
    | false => {
      format!(":{}", label.dimmed())
    },
  }
}

impl std::fmt::Debug for Stack {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    let (ty, flags): (String, String) = match self {
      | Stack::Root => (format!("{}", "R".bright_magenta()), "".to_string()),
      | Stack::Node {
        has_fields,
        last_node,
      } => {
        (
          format!("{}", "N".bright_green()),
          [format_flag("LC", last_node), format_flag("HF", has_fields)]
            .join(":"),
        )
      },
      | Stack::Leaf {
        has_fields,
        last_node,
      } => {
        (
          format!("{}", "L".bright_yellow()),
          [format_flag("LC", last_node), format_flag("HF", has_fields)]
            .join(":"),
        )
      },
      | Stack::Divider => (format!("{}", "D".bright_cyan()), "".to_string()),
      | Stack::LeafField {
        last_node,
        first_field,
        last_field,
      } => {
        (
          format!("{}", "F".bright_red()),
          [
            format_flag("LC", last_node),
            format_flag("FF", first_field),
            format_flag("LF", last_field),
          ]
          .join(":"),
        )
      },
      | Stack::NodeField {
        last_node,
        first_field,
        last_field,
      } => {
        (
          format!("{}", "NF".bright_blue()),
          [
            format_flag("LC", last_node),
            format_flag("FF", first_field),
            format_flag("LF", last_field),
          ]
          .join(":"),
        )
      },
      | Stack::Nodes {
        first_node,
        last_node,
        has_nodes,
      } => {
        (
          format!("{}", "C".bright_blue()),
          [
            format_flag("FC", first_node),
            format_flag("LC", last_node),
            format_flag("HC", last_node),
          ]
          .join(":"),
        )
      },
      | Stack::BlankLine => (format!("{}", "B".bright_cyan()), "".to_string()),
    };

    write!(
      f,
      "{open}{ty}{flags}{close}",
      open = "[".dimmed(),
      close = "]".dimmed(),
    )
  }
}

#[derive(Clone, PartialEq)]
enum GlyphWithColor {
  None(Glyph),
  Node(Glyph),
  Leaf(Glyph),
  Field(Glyph),
  Nodes(Glyph),
}
impl GlyphWithColor {
  fn style(&self, styles: &Styles) -> String {
    match self {
      | GlyphWithColor::None(glyph) => glyph.to_string(),
      | GlyphWithColor::Node(glyph) => {
        glyph.clone().style(styles.trivia_node).to_string()
      },
      | GlyphWithColor::Leaf(glyph) => {
        glyph.clone().style(styles.trivia_leaf).to_string()
      },
      | GlyphWithColor::Field(glyph) => {
        glyph.clone().style(styles.trivia_field).to_string()
      },
      | GlyphWithColor::Nodes(glyph) => {
        glyph.clone().style(styles.trivia_nodes).to_string()
      },
    }
  }
}

impl std::fmt::Display for GlyphWithColor {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "{}", match self {
      | GlyphWithColor::None(glyph) => glyph,
      | GlyphWithColor::Node(glyph) => glyph,
      | GlyphWithColor::Leaf(glyph) => glyph,
      | GlyphWithColor::Field(glyph) => glyph,
      | GlyphWithColor::Nodes(glyph) => glyph,
    })
  }
}

impl std::fmt::Debug for GlyphWithColor {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    write!(f, "{:?}", match self {
      | GlyphWithColor::None(glyph) => glyph,
      | GlyphWithColor::Node(glyph) => glyph,
      | GlyphWithColor::Leaf(glyph) => glyph,
      | GlyphWithColor::Field(glyph) => glyph,
      | GlyphWithColor::Nodes(glyph) => glyph,
    })
  }
}

// TODO: config to replace icons (gold-3wq)
pub(crate) struct Prefix<'a> {
  styles:    &'a Styles,
  pub stack: Vec<Stack>,
}

impl<'a> Prefix<'a> {
  pub fn new(styles: &'a Styles) -> Self {
    Self {
      styles,
      stack: vec![],
    }
  }

  pub fn is_empty(&self) -> bool {
    self.stack.is_empty()
  }

  pub fn len(&self) -> usize {
    self.stack.len()
  }
}

impl<'a> Prefix<'a> {
  pub fn push_stack_node(&mut self, has_fields: bool, last_mpde: bool) {
    self.stack.push(Stack::Node {
      has_fields,
      last_node: last_mpde,
    });
  }

  pub fn push_stack_leaf(&mut self, has_fields: bool, last_node: bool) {
    self.stack.push(Stack::Leaf {
      has_fields,
      last_node,
    });
  }

  pub fn push_stack_divider(&mut self) {
    self.stack.push(Stack::Divider);
  }

  pub fn push_stack_blank(&mut self) {
    self.stack.push(Stack::BlankLine);
  }

  pub fn push_stack_field(
    &mut self,
    is_for_node: bool,
    first_field: bool,
    last_field: bool,
    last_node: bool,
  ) {
    if is_for_node {
      self.stack.push(Stack::NodeField {
        last_node,
        first_field,
        last_field,
      });
    } else {
      self.stack.push(Stack::LeafField {
        last_node,
        first_field,
        last_field,
      });
    }
  }

  pub fn push_stack_nodes(
    &mut self,
    first_node: bool,
    last_node: bool,
    has_nodes: bool,
  ) {
    self.stack.push(Stack::Nodes {
      first_node,
      last_node,
      has_nodes,
    });
  }

  pub fn pop_stack(&mut self) {
    self.stack.pop();
  }

  pub fn render_prefix_stack(
    &mut self,
    w: &mut Writer,
    style: &Styles,
  ) -> std::fmt::Result {
    let len = self.stack.len();

    let mut debug_buf: Vec<String> = vec![];
    let mut g: Vec<GlyphWithColor> = vec![];
    let mut prefix_stack = self.stack.clone();

    for (i, stack) in self.stack.iter().enumerate() {
      let is_first = i == 0;
      let is_last = i == (len - 1);

      debug_buf.push(format!("{i}:{:?}{}", stack, {
        let last = if is_last {
          "L".bright_white().to_string()
        } else {
          "L".dimmed().to_string()
        };

        last
      }));

      match stack {
        | Stack::Root => {
          g.push(GlyphWithColor::None(Glyph::RootCollapse));
          g.push(GlyphWithColor::None(Glyph::RootCollapse));
        },
        | Stack::Node {
          has_fields,
          last_node,
        } => {
          if is_last {
            if i == 0 && len == 1 {
              // root node
              g.push(GlyphWithColor::Node(Glyph::Root));
              g.push(GlyphWithColor::Node(Glyph::LightHorizontal));
            } else if *last_node {
              g.push(GlyphWithColor::Node(Glyph::LightUpRight));
              g.push(GlyphWithColor::Node(Glyph::LightHorizontal));
            } else {
              g.push(GlyphWithColor::Node(Glyph::LightVerticalRight));
              g.push(GlyphWithColor::Node(Glyph::LightHorizontal));
            }
          } else if *last_node {
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::None(Glyph::Blank));
          } else {
            g.push(GlyphWithColor::Node(Glyph::LightVertical));
            g.push(GlyphWithColor::None(Glyph::Blank));
          }
        },
        | Stack::Leaf {
          has_fields,
          last_node,
        } => {
          if is_last {
            if i == 0 && len == 1 {
              g.push(GlyphWithColor::Leaf(Glyph::Root));
              g.push(GlyphWithColor::Leaf(Glyph::LightHorizontal));
            } else if *last_node {
              g.push(GlyphWithColor::Leaf(Glyph::LightUpRight));
              g.push(GlyphWithColor::Leaf(Glyph::LightHorizontal));
            } else {
              g.push(GlyphWithColor::Leaf(Glyph::LightVerticalRight));
              g.push(GlyphWithColor::Leaf(Glyph::LightHorizontal));
            }
          } else if *last_node {
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::None(Glyph::Blank));
          } else {
            g.push(GlyphWithColor::Leaf(Glyph::LightVertical));
            g.push(GlyphWithColor::None(Glyph::Blank));
          }
        },
        // -- Fields -----------------------------------------------------------
        | Stack::Divider => {
          g.push(GlyphWithColor::None(Glyph::Blank));
          g.push(GlyphWithColor::None(Glyph::Blank));
        },

        | Stack::LeafField {
          last_node,
          first_field,
          last_field,
        } => {
          g.push(GlyphWithColor::None(Glyph::Blank));
          g.push(GlyphWithColor::None(Glyph::Blank));
          g.push(GlyphWithColor::Field(Glyph::Dash));
          g.push(GlyphWithColor::None(Glyph::Blank));
        },
        | Stack::NodeField { last_node, .. } => {
          if is_last {
            g.push(GlyphWithColor::Field(Glyph::LightVertical));
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::Field(Glyph::Dash));
            g.push(GlyphWithColor::None(Glyph::Blank));
          } else {
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::Field(Glyph::Dash));
            g.push(GlyphWithColor::None(Glyph::Blank));
          }
        },
        | Stack::Nodes {
          first_node,
          last_node,
          has_nodes,
        } => {
          if is_last {
            match (*first_node, *last_node) {
              // first_node, last_node
              | (true, true) => {
                g.push(GlyphWithColor::Nodes(Glyph::LightUpRight)); // ╾
                g.push(GlyphWithColor::Nodes(Glyph::LightHorizontal));
              },
              // first_node
              | (true, false) => {
                g.push(GlyphWithColor::Nodes(Glyph::LightVerticalRight));
                g.push(GlyphWithColor::Nodes(Glyph::LightHorizontal));
              },
              // last_node
              | (false, true) => {
                g.push(GlyphWithColor::Nodes(Glyph::LightUpRight));
                g.push(GlyphWithColor::Nodes(Glyph::LightHorizontal));
              },
              | (false, false) => {
                g.push(GlyphWithColor::Nodes(Glyph::LightVerticalRight));
                g.push(GlyphWithColor::Nodes(Glyph::LightHorizontal));
              },
            }
          } else if *last_node {
            g.push(GlyphWithColor::None(Glyph::Blank));
            g.push(GlyphWithColor::None(Glyph::Blank));
          } else {
            g.push(GlyphWithColor::Nodes(Glyph::LightVertical));
            g.push(GlyphWithColor::None(Glyph::Blank));
          }
        },

        | Stack::BlankLine => {
          g.push(GlyphWithColor::None(Glyph::Blank));
          g.push(GlyphWithColor::None(Glyph::Blank));

          // remove trailing blanks
          while g.last() == Some(&GlyphWithColor::None(Glyph::Blank)) {
            g.pop();
          }
        },
      }
    }

    w.write_prefix(format!(
      "{}",
      g.iter()
        .map(|gl| { gl.style(self.styles) })
        .collect::<Vec<String>>()
        .join("")
        .style(style.lines),
    ))?;

    // if simple_debug {
    //   w.write_debug(debug_buf.join(" "));
    // }

    let show_prefix_debug = false;
    if show_prefix_debug {
      w.write_debug({
        let mut out = String::new();
        let g_chunks = g.chunks(2).map(|gvec| format!("{gvec:?}"));

        let mut d_chunks = debug_buf.iter();

        for chunk in g_chunks {
          if let Some(chnk) = d_chunks.next() {
            out.push_str(chnk);
            out.push(' ');
          }
          out.push_str(chunk.to_string().as_str());
          // out.push(' ');
          // out.push(' ');
          out.push(' ');
        }
        for chnk in d_chunks {
          out.push_str(chnk);
          out.push(' ');
        }

        out
      })?;
    }

    Ok(())
  }
}
