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

use owo_colors::{
  OwoColorize,
  Style,
};

/// Configuration for styling the output of tree rendering.
///
/// The `Styles` struct controls all aspects of the visual appearance of
/// rendered trees, including colors, spacing, line numbers, and various
/// UI elements. It provides fine-grained control over how different parts
/// of the tree are displayed.
///
/// # Examples
///
/// ```rust
/// use {
///   bluegum::{
///     Printer,
///     Styles,
///   },
///   owo_colors::Style,
/// };
///
/// let mut styles = Styles::default();
/// styles.hide_line_numbers = true;
/// styles.type_name = Style::new().red().bold();
///
/// let printer = Printer::new(styles);
/// ```
///
/// # Style Categories
///
/// The styles are organized into several categories:
/// - **Content styles**: Control the appearance of node names, fields, and
///   values
/// - **UI styles**: Control prefixes, lines, icons, and structural elements
/// - **Layout options**: Control spacing, alignment, and visibility of elements
/// - **Debug options**: Control debug information display
pub struct Styles {
  /// Style for tree structure prefixes (the lines and connectors)
  pub prefix:             Style,
  /// Style for node type names (the main labels)
  pub type_name:          Style,
  /// Style for dimmed/secondary node type information
  pub type_name_trivia:   Style,
  /// Style for node collection labels (like "children", "items")
  pub nodes_label:        Style,
  /// Style for dimmed node collection information
  pub nodes_label_trivia: Style,
  /// Style for field names (the keys in key-value pairs)
  pub field_name:         Style,
  /// Style for field values (the values in key-value pairs)
  pub field_value:        Style,
  /// Style for alternate values (right-aligned additional info)
  pub alt_value:          Style,
  /// Whether to align alternate values to the right
  pub align_alt:          bool,
  /// Style for debug information names
  pub debug_name:         Style,
  /// Style for debug information values
  pub debug_value:        Style,
  /// Style for general trivia/secondary information
  pub trivia:             Style,
  /// Style for length tags (e.g., "[len=5]")
  pub trivia_len_tag:     Style,
  /// Style for node-related trivia
  pub trivia_node:        Style,
  /// Style for leaf-related trivia
  pub trivia_leaf:        Style,
  /// Style for field-related trivia
  pub trivia_field:       Style,
  /// Style for nodes collection trivia
  pub trivia_nodes:       Style,
  /// Style for root node icons
  pub icon_root:          Style,
  /// Style for regular node icons
  pub icon_node:          Style,
  /// Style for fragment node icons
  pub icon_fragment:      Style,
  /// Style for leaf node icons
  pub icon_leaf:          Style,
  /// Style for tree structure lines
  pub lines:              Style,
  /// Style for line numbers
  pub line_numbers:       Style,

  /// Hide the connecting lines between nodes.
  /// When true, indentation is applied using 2 spaces instead of line
  /// characters.
  pub hide_lines:          bool,
  /// Hide line numbers from the output.
  pub hide_line_numbers:   bool,
  /// Show debug information when available.
  pub show_debug:          bool,
  /// Maximum spaces to pad debug output for alignment.
  /// Debug output larger than this value will not be aligned properly.
  pub max_debug_pad:       usize,
  /// Add a blank line after each node for better visual separation.
  pub new_line_after_node: bool,
  /// Enable verbose mode with additional details and spacing.
  pub verbose:             bool,
}

impl Styles {
  /// Create a new `Styles` configuration with default styling.
  ///
  /// This creates a visually appealing default configuration with:
  /// - Colored output using various ANSI colors
  /// - Line numbers and connecting lines enabled
  /// - Debug information enabled
  /// - Verbose mode enabled
  ///
  /// # Examples
  ///
  /// ```rust
  /// use bluegum::Styles;
  ///
  /// let styles = Styles::new();
  /// assert_eq!(styles.hide_line_numbers, false);
  /// assert_eq!(styles.verbose, true);
  /// ```
  pub fn new() -> Self {
    Self {
      prefix:             Style::new().remove_all_effects().white().dimmed(),
      type_name:          Style::new().remove_all_effects().yellow(),
      type_name_trivia:   Style::new().remove_all_effects().yellow().dimmed(),
      nodes_label:        Style::new().remove_all_effects().magenta().dimmed(),
      nodes_label_trivia: Style::new().remove_all_effects().magenta().dimmed(),
      field_name:         Style::new().remove_all_effects().purple().dimmed(),
      field_value:        Style::new()
        .remove_all_effects()
        .white()
        .dimmed()
        .italic(),
      alt_value:          Style::new().remove_all_effects().bright_white(),
      align_alt:          true,
      debug_name:         Style::new().remove_all_effects().yellow().dimmed(),
      debug_value:        Style::new().remove_all_effects().white(),
      trivia:             Style::new().remove_all_effects().purple().dimmed(),
      trivia_len_tag:     Style::new().remove_all_effects().magenta(),
      trivia_node:        Style::new().remove_all_effects().magenta().dimmed(),
      trivia_leaf:        Style::new().remove_all_effects().magenta().dimmed(),
      trivia_field:       Style::new().remove_all_effects().magenta().dimmed(),
      trivia_nodes:       Style::new().remove_all_effects().magenta().dimmed(),

      icon_root:     Style::new().remove_all_effects().magenta().dimmed(),
      icon_node:     Style::new().remove_all_effects().yellow().dimmed(),
      icon_fragment: Style::new().remove_all_effects().magenta().dimmed(),
      icon_leaf:     Style::new().remove_all_effects().magenta().dimmed(),
      lines:         Style::new().remove_all_effects().magenta().dimmed(),
      line_numbers:  Style::new().remove_all_effects().dimmed(),

      hide_lines:        false,
      hide_line_numbers: false,
      show_debug:        true,
      max_debug_pad:     240,

      new_line_after_node: true,
      verbose:             true,
    }
  }

  pub fn compact() -> Styles {
    Self {
      max_debug_pad: 80,
      ..Default::default()
    }
  }
}

impl Default for Styles {
  fn default() -> Self {
    Self::new()
  }
}
