use super::{
	ast,
	tok::{Token, TokenKind, Tokens},
};

#[derive(Debug)]
pub struct Tree {
	nodes: Vec<Node>,
}
impl Tree {
	pub fn new() -> Self {
		let mut out = Self { nodes: vec![] };
		out.register({
			let mut node = Node::unregistered();
			node.kind = NodeKind::Root;

			node
		});

		out
	}

	pub fn register(&mut self, mut node: Node) -> NodeRef {
		node.id = self.nodes.len();
		let out = NodeRef(node.id);

		self.nodes.push(node);

		out
	}

	pub fn root(&self) -> NodeRef {
		NodeRef(0)
	}

	pub fn add_child(&mut self, parent: NodeRef, child: NodeRef) {
		parent.resolve_mut(self).children.push(child);
		child.resolve_mut(self).parent = Some(parent);
	}

	pub fn nth_child(
		&self,
		parent: NodeRef,
		child_index: usize,
	) -> Option<NodeRef> {
		parent.resolve(self).children.get(child_index).copied()
	}

	pub fn children_of(
		&self,
		parent: NodeRef,
	) -> impl Iterator<Item = NodeRef> {
		parent.resolve(self).children.iter().copied()
	}
}

#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct NodeRef(usize);
impl NodeRef {
	fn resolve<'a>(&self, tree: &'a Tree) -> &'a Node {
		&tree.nodes[self.0]
	}

	fn resolve_mut<'a>(&self, tree: &'a mut Tree) -> &'a mut Node {
		&mut tree.nodes[self.0]
	}
}

#[derive(Default, Debug)]
pub struct Node {
	id: usize,
	parent: Option<NodeRef>,
	children: Vec<NodeRef>,
	kind: NodeKind,
	whitespace: Option<Token>,
	token: Option<Token>,
}
impl Node {
	fn unregistered() -> Self {
		Self {
			id: usize::MAX,
			parent: None,
			children: vec![],
			kind: NodeKind::Unknown,
			whitespace: None,
			token: None,
		}
	}

	pub fn kind(&self) -> &NodeKind {
		&self.kind
	}

	pub fn token(&self) -> Option<&Token> {
		self.token.as_ref()
	}
}

#[derive(Default, Debug, Eq, PartialEq)]
pub enum NodeKind {
	#[default]
	Unknown,
	List,
	Token,
	Atom,
	Root,
}

pub fn parse(corpus: &str) -> Tree {
	let mut tree = Tree::new();
	let mut tokens = Tokens::new(corpus);

	while let Some(nr) = parse_one(&mut tree, &mut tokens) {
		let root = tree.root();
		tree.add_child(root, nr);
	}

	tree
}

pub fn parse_one(tree: &mut Tree, tokens: &mut Tokens) -> Option<NodeRef> {
	let tok = tokens.next()?;
	let (ws, tok) = match tok.kind {
		TokenKind::Whitespace(_) => (Some(tok), tokens.next()),
		_ => (None, Some(tok)),
	};

	let mut node = Node::unregistered();
	node.whitespace = ws;
	let tok = match tok {
		Some(tok) => tok,
		None => {
			node.kind = NodeKind::Token;
			return Some(tree.register(node));
		},
	};

	match &tok.kind {
		TokenKind::Atom(_) => {
			node.kind = NodeKind::Atom;
		},
		_ => todo!(),
	}

	node.token = Some(tok);

	Some(tree.register(node))
}

#[cfg(test)]
mod test {
	use crate::syn::{
		cst::NodeKind,
		tok::{Atom, TokenKind},
	};

	use super::parse;

	#[test]
	fn atom1() {
		let tree = parse("32");
		let mut children =
			tree.children_of(tree.root()).map(|n| n.resolve(&tree));

		let first = children.next().unwrap().as_atom().unwrap().value();
	}
}
