use std::{fmt::Display, ops::Range};

pub enum Text {
	Span(Range<usize>),
	Static(&'static str),
	String(String),
}
impl Default for Text {
	fn default() -> Self {
		Self::Static("")
	}
}

impl Text {
	pub fn empty() -> Self {
		Self::default()
	}

	pub fn is_empty(&self) -> bool {
		match self {
			Self::Span(s) => s.is_empty(),
			Self::Static(s) => s.is_empty(),
			Self::String(s) => s.is_empty(),
		}
	}

	pub fn as_str<'a>(&'a self, text: &'a str) -> &'a str {
		match self {
			Self::Span(s) => &text[s.clone()],
			Self::Static(s) => s,
			Self::String(s) => s.as_str(),
		}
	}
}

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct NodeRef(usize);
#[derive(Default)]
pub struct NodeStorage {
	tags: Vec<u16>,
	parents: Vec<Option<NodeRef>>,
	children: Vec<Vec<NodeRef>>,
	siblings_prev: Vec<Option<NodeRef>>,
	siblings_next: Vec<Option<NodeRef>>,
	texts: Vec<Text>,
}
impl NodeStorage {
	pub fn nodes(&self) -> impl Iterator<Item = NodeRef> {
		(0..self.tags.len()).map(NodeRef)
	}

	pub fn new_node(&mut self, tag: u16) -> NodeRef {
		let node = NodeRef(self.tags.len());
		self.tags.push(tag);
		self.parents.push(None);
		self.children.push(vec![]);
		self.siblings_prev.push(None);
		self.siblings_next.push(None);
		self.texts.push(Text::default());

		node
	}

	pub fn tag(&self, node: NodeRef) -> u16 {
		self.tags[node.0]
	}

	pub fn parent(&self, node: NodeRef) -> Option<NodeRef> {
		self.parents[node.0]
	}

	pub fn set_parent(&mut self, child: NodeRef, parent: NodeRef) {
		self.parents[child.0] = Some(parent);
	}

	pub fn children(&self, node: NodeRef) -> impl Iterator<Item = NodeRef> {
		self.children[node.0].iter().copied()
	}

	pub fn append_child(&mut self, parent: NodeRef, child: NodeRef) {
		self.set_parent(child, parent);

		let children = &mut self.children[parent.0];
		let child_index = children.len();

		children.push(child);

		if child_index > 0 {
			let prev_index = child_index - 1;
			let prev_sibling = children[prev_index];
			self.set_sibling_next(prev_sibling, child);
			self.set_sibling_prev(child, prev_sibling);
		}
	}

	pub fn sibling_next(&mut self, node: NodeRef) -> Option<NodeRef> {
		self.siblings_next[node.0]
	}

	pub fn set_sibling_next(&mut self, this: NodeRef, next: NodeRef) {
		self.siblings_next[this.0] = Some(next);
	}

	pub fn sibling_prev(&mut self, node: NodeRef) -> Option<NodeRef> {
		self.siblings_prev[node.0]
	}

	pub fn set_sibling_prev(&mut self, this: NodeRef, prev: NodeRef) {
		self.siblings_prev[this.0] = Some(prev);
	}

	pub fn text(&self, node: NodeRef) -> &Text {
		&self.texts[node.0]
	}

	pub fn set_text(&mut self, node: NodeRef, text: Text) {
		self.texts[node.0] = text;
	}

	pub fn display_syntax<'a>(
		&'a self,
		text: &'a str,
		node: NodeRef,
	) -> impl Display + 'a {
		struct DisplaySyntax<'a> {
			nodes: &'a NodeStorage,
			node: NodeRef,
			text: &'a str,
		}

		impl Display for DisplaySyntax<'_> {
			fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
				let s = match self.nodes.text(self.node) {
					Text::Span(s) => &self.text[s.clone()],
					Text::Static(s) => s,
					Text::String(s) => s.as_str(),
				};

				write!(f, "{s}")?;
				for child in self.nodes.children(self.node) {
					write!(
						f,
						"{}",
						self.nodes.display_syntax(self.text, child)
					)?;
				}

				Ok(())
			}
		}

		DisplaySyntax {
			nodes: self,
			node,
			text,
		}
	}
}

impl NodeStorage {
	pub fn new() -> Self {
		Self::default()
	}
}
