//! Implementations of `TreeDisplay` for common Rust types.
//!
//! This module provides `TreeDisplay` implementations for:
//! - Primitive types (bool, char, integers, floats, etc.)
//! - Standard library collections (Vec, HashMap, HashSet, etc.)
//! - Smart pointers (Box, Rc, Arc, RefCell, etc.)
//! - Common types (Option, Result, tuples, ranges, etc.)
//! - Path and time types
//!
//! ## Feature Flags
//! - `chumsky`: Enables support for `chumsky::span::SimpleSpan`

use crate::{
  context::Context,
  format::{Content, Index, Keyword, Member, TypeName},
  Tree, TreeDisplay,
};

mod support {
  use super::*;

  /// Implements `TreeDisplay` for primitive types by rendering them as leaf nodes.
  macro_rules! impl_tree_display_for_primitive {
    ($($ty:ty),* $(,)?) => {
      $(
        impl TreeDisplay for $ty {
          fn tree(&self, _: &Context) -> Tree {
            Tree::leaf(self.clone())
          }
        }
      )*
    };
  }

  impl_tree_display_for_primitive!(
    bool,
    char,
    String,
    i8,
    i16,
    i32,
    i64,
    i128,
    isize,
    u8,
    u16,
    u32,
    u64,
    u128,
    usize,
    f32,
    f64,
    std::num::NonZeroU8,
    std::num::NonZeroU16,
    std::num::NonZeroU32,
    std::num::NonZeroU64,
    std::num::NonZeroU128,
    std::num::NonZeroUsize,
    std::num::NonZeroI8,
    std::num::NonZeroI16,
    std::num::NonZeroI32,
    std::num::NonZeroI64,
    std::num::NonZeroI128,
    std::num::NonZeroIsize,
  );

  /// Implements `TreeDisplay` for tuples up to 12 elements.
  ///
  /// Each tuple element is displayed as a labeled child with an index.
  macro_rules! impl_tuple_tree_display {
    ($($ty:ident $idx:tt),*) => {
      impl<$($ty: TreeDisplay),*> TreeDisplay for ($($ty,)*) {
        #[allow(unused_variables)] // supress erroneous warning
        fn tree(&self, context: &Context) -> Tree {
          #[allow(unused_mut)] // supress erroneous warning
          let mut tree = Tree::leaf(TypeName::new("tuple"));
          $(
            let node = self.$idx.tree(context).labeled(Member(format!(".{}", $idx)));
            tree.subtrees.push(node);
          )*
          tree
        }
      }
  };
  }

  // Manual expansion for each tuple size
  impl_tuple_tree_display!();
  impl_tuple_tree_display!(T0 0);
  impl_tuple_tree_display!(T0 0, T1 1);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6, T7 7);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6, T7 7, T8 8);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6, T7 7, T8 8, T9 9);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6, T7 7, T8 8, T9 9, T10 10);
  impl_tuple_tree_display!(T0 0, T1 1, T2 2, T3 3, T4 4, T5 5, T6 6, T7 7, T8 8, T9 9, T10 10, T11 11);

  /// `&str` is displayed as a string leaf, not a tree of characters.
  impl TreeDisplay for &str {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(ToString::to_string(&self))
    }
  }

  // ──── Smart pointers ──────────────────────────────────────────────────────────────────────────

  impl<T: TreeDisplay + ?Sized> TreeDisplay for &T {
    fn tree(&self, context: &Context) -> Tree {
      (**self).tree(context)
    }
  }

  impl<T: TreeDisplay + ?Sized> TreeDisplay for &mut T {
    fn tree(&self, context: &Context) -> Tree {
      (**self).tree(context)
    }
  }

  impl<T: TreeDisplay + ?Sized> TreeDisplay for Box<T> {
    fn tree(&self, context: &Context) -> Tree {
      (**self).tree(context)
    }
  }

  impl<T: TreeDisplay + ?Sized> TreeDisplay for std::rc::Rc<T> {
    fn tree(&self, context: &Context) -> Tree {
      (**self).tree(context)
    }
  }

  impl<T: TreeDisplay + ?Sized> TreeDisplay for std::sync::Arc<T> {
    fn tree(&self, context: &Context) -> Tree {
      (**self).tree(context)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::cell::RefCell<T> {
    fn tree(&self, context: &Context) -> Tree {
      self.borrow().tree(context)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::sync::Mutex<T> {
    fn tree(&self, context: &Context) -> Tree {
      self.lock().unwrap().tree(context)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::sync::RwLock<T> {
    fn tree(&self, context: &Context) -> Tree {
      self.read().unwrap().tree(context)
    }
  }

  // ──── Option and Result ───────────────────────────────────────────────────────────────────────

  impl<T: TreeDisplay> TreeDisplay for Option<T> {
    fn tree(&self, context: &Context) -> Tree {
      match self {
        Some(value) => value.tree(context),
        None => Tree::leaf(Keyword::new("None")),
      }
    }
  }

  impl<T: TreeDisplay, E: TreeDisplay> TreeDisplay for Result<T, E> {
    fn tree(&self, context: &Context) -> Tree {
      match self {
        Ok(value) => value.tree(context),
        Err(err) => err.tree(context),
      }
    }
  }

  // ──── Collections ─────────────────────────────────────────────────────────────────────────────

  impl<T: TreeDisplay, const N: usize> TreeDisplay for [T; N] {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .enumerate()
        .map(|(i, item)| item.tree(context).labeled(Index::new(i)))
        .collect();
      let len_node = Tree::leaf(N).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("Array"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for [T] {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .enumerate()
        .map(|(i, item)| item.tree(context).labeled(Index::new(i)))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("Slice"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for Vec<T> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .enumerate()
        .map(|(i, item)| item.tree(context).labeled(Index::new(i)))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("Vec"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::collections::VecDeque<T> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .enumerate()
        .map(|(i, item)| item.tree(context).labeled(Index::new(i)))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("VecDeque"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::collections::LinkedList<T> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .enumerate()
        .map(|(i, item)| item.tree(context).labeled(Index::new(i)))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("LinkedList"), children)
    }
  }

  impl<K: Clone + Content, V: TreeDisplay, S> TreeDisplay for std::collections::HashMap<K, V, S> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .map(|(key, value)| value.tree(context).labeled(Index::new(key.clone())))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("HashMap"), children)
    }
  }

  impl<K: Clone + Content, V: TreeDisplay> TreeDisplay for std::collections::BTreeMap<K, V> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self
        .iter()
        .map(|(key, value)| value.tree(context).labeled(Index::new(key.clone())))
        .collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("BTreeMap"), children)
    }
  }

  impl<T: TreeDisplay, S> TreeDisplay for std::collections::HashSet<T, S> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self.iter().map(|item| item.tree(context)).collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("HashSet"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::collections::BTreeSet<T> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self.iter().map(|item| item.tree(context)).collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("BTreeSet"), children)
    }
  }

  impl<T: TreeDisplay> TreeDisplay for std::collections::BinaryHeap<T> {
    fn tree(&self, context: &Context) -> Tree {
      let mut children: Vec<Tree> = self.iter().map(|item| item.tree(context)).collect();
      let len_node = Tree::leaf(self.len()).labeled(Member::new("len"));
      children.insert(0, len_node);
      Tree::new(TypeName::new("BinaryHeap"), children)
    }
  }

  // ──── Path and file types ─────────────────────────────────────────────────────────────────────

  impl TreeDisplay for std::path::Path {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  impl TreeDisplay for std::path::PathBuf {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  impl TreeDisplay for std::ffi::OsString {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  impl TreeDisplay for std::ffi::OsStr {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  // ──── Time types ──────────────────────────────────────────────────────────────────────────────

  impl TreeDisplay for std::time::Duration {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{}s", self.as_secs_f64()))
    }
  }

  impl TreeDisplay for std::time::Instant {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  impl TreeDisplay for std::time::SystemTime {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(format!("{:?}", self))
    }
  }

  // ──── Range types ─────────────────────────────────────────────────────────────────────────

  impl<T: TreeDisplay + std::fmt::Debug + Clone + 'static> TreeDisplay for std::ops::Range<T> {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![
        Tree::leaf(self.start.clone()).labeled(Member::new("start")),
        Tree::leaf(self.end.clone()).labeled(Member::new("end")),
      ];
      Tree::new(TypeName::new("Range"), children)
    }
  }

  impl<T: TreeDisplay + std::fmt::Debug + Clone + 'static> TreeDisplay
    for std::ops::RangeInclusive<T>
  {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![
        Tree::leaf(self.start().clone()).labeled(Member::new("start")),
        Tree::leaf(self.end().clone()).labeled(Member::new("end")),
      ];
      Tree::new(TypeName::new("RangeInclusive"), children)
    }
  }

  impl<T: TreeDisplay + std::fmt::Debug + Clone + 'static> TreeDisplay for std::ops::RangeFrom<T> {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![Tree::leaf(self.start.clone()).labeled(Member::new("start"))];
      Tree::new(TypeName::new("RangeFrom"), children)
    }
  }

  impl<T: TreeDisplay + std::fmt::Debug + Clone + 'static> TreeDisplay for std::ops::RangeTo<T> {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![Tree::leaf(self.end.clone()).labeled(Member::new("end"))];
      Tree::new(TypeName::new("RangeTo"), children)
    }
  }

  impl<T: TreeDisplay + std::fmt::Debug + Clone + 'static> TreeDisplay
    for std::ops::RangeToInclusive<T>
  {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![Tree::leaf(self.end.clone()).labeled(Member::new("end"))];
      Tree::new(TypeName::new("RangeToInclusive"), children)
    }
  }

  impl TreeDisplay for std::ops::RangeFull {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(TypeName::new("RangeFull"))
    }
  }

  // ──── Marker types ────────────────────────────────────────────────────────────────────────────

  impl<T> TreeDisplay for std::marker::PhantomData<T> {
    fn tree(&self, _: &Context) -> Tree {
      Tree::leaf(TypeName::new("PhantomData"))
    }
  }
}

#[cfg(feature = "chumsky")]
mod chumsky_support {
  use super::*;
  use chumsky::span::SimpleSpan;

  impl TreeDisplay for SimpleSpan {
    fn tree(&self, _: &Context) -> Tree {
      let children = vec![
        Tree::leaf(self.start).labeled(Member::new("start")),
        Tree::leaf(self.end).labeled(Member::new("end")),
      ];
      Tree::new(TypeName::new("SimpleSpan"), children)
    }
  }
}
