use indextree::{Node, NodeId};
use smallvec::{SmallVec, smallvec};

use super::*;
use crate::{
  data_widget::{AnonymousAttacher, DataAttacher},
  window::DelayEvent,
};

#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug, Hash)]
#[cfg_attr(feature = "debug", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "debug", serde(transparent))]
pub struct WidgetId(pub(crate) NodeId);

// A place holder get from a `WidgetId`, you can use it to insert a widget
// replace the `WidgetId` you get this place holder.
pub(crate) enum PlaceHolder {
  PrevSibling(WidgetId),
  NextSibling(WidgetId),
  Parent(WidgetId),
}

pub trait RenderQueryable: Render + Query {
  fn as_render(&self) -> &dyn Render;
}

impl<T: Render + Query> RenderQueryable for T {
  fn as_render(&self) -> &dyn Render { self }
}

/// You can get TrackId by builtin method of track_id().
/// see [`TrackWidgetId::track_id`]
pub struct TrackId(Stateful<Option<WidgetId>>);

impl TrackId {
  pub fn get(&self) -> Option<WidgetId> { *self.0.read() }

  pub fn clone_watcher(&self) -> Watcher<Reader<Option<WidgetId>>> { self.0.clone_watcher() }

  pub(crate) fn set(&self, id: Option<WidgetId>) { *self.0.write() = id; }
}

impl dyn RenderQueryable {
  pub(crate) fn update_track_id(&self, new_id: WidgetId) {
    let mut handles = SmallVec::new();
    self.query_all(&QueryId::of::<TrackId>(), &mut handles);
    handles
      .into_iter()
      .filter_map(QueryHandle::into_ref::<TrackId>)
      .for_each(move |q| q.set(Some(new_id)));
  }
}

impl Default for TrackId {
  fn default() -> Self { Self(Stateful::new(None)) }
}

impl Clone for TrackId {
  fn clone(&self) -> Self { Self(self.0.clone_writer()) }
}

impl PartialEq for TrackId {
  fn eq(&self, other: &Self) -> bool { Stateful::ptr_eq(&self.0, &other.0) }
}

impl WidgetId {
  /// Returns a reference to the node data.
  pub(crate) fn get<'a, 'b>(self, tree: &'a WidgetTree) -> Option<&'a (dyn RenderQueryable + 'b)> {
    tree.arena.get(self.0).map(|n| &**n.get())
  }

  pub(crate) fn get_node_mut(self, tree: &mut WidgetTree) -> Option<&mut Box<dyn RenderQueryable>> {
    tree.arena.get_mut(self.0).map(|n| n.get_mut())
  }

  /// detect if the widget of this id point to is dropped.
  pub(crate) fn is_dropped(self, tree: &WidgetTree) -> bool { self.0.is_removed(&tree.arena) }

  pub(crate) fn lowest_common_ancestor(
    self, other: WidgetId, tree: &WidgetTree,
  ) -> Option<WidgetId> {
    self.common_ancestors(other, tree).last()
  }

  // return ancestors from root to lowest common ancestor
  pub(crate) fn common_ancestors(
    self, other: WidgetId, tree: &WidgetTree,
  ) -> impl Iterator<Item = WidgetId> + '_ {
    let mut p0 = vec![];
    let mut p1 = vec![];
    if !self.is_dropped(tree) && !other.is_dropped(tree) {
      p0 = other.ancestors(tree).collect::<Vec<_>>();
      p1 = self.ancestors(tree).collect::<Vec<_>>();
    }

    p0.into_iter()
      .rev()
      .zip(p1.into_iter().rev())
      .take_while(|(a, b)| a == b)
      .map(|(a, _)| a)
  }

  pub(crate) fn place_holder(self, tree: &WidgetTree) -> PlaceHolder {
    if let Some(prev) = self.prev_sibling(tree) {
      PlaceHolder::PrevSibling(prev)
    } else if let Some(next) = self.next_sibling(tree) {
      PlaceHolder::NextSibling(next)
    } else {
      PlaceHolder::Parent(self.parent(tree).unwrap())
    }
  }

  pub(crate) fn tree_parent(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, |node| node.parent())
  }

  fn detached_parent(self, tree: &WidgetTree) -> Option<WidgetId> {
    if self == tree.root() {
      return None;
    }

    tree
      .detached_parent(self)
      .filter(|parent| !parent.is_dropped(tree))
  }

  pub(crate) fn parent(self, tree: &WidgetTree) -> Option<WidgetId> {
    self
      .tree_parent(tree)
      .or_else(|| self.detached_parent(tree))
  }

  pub(crate) fn first_child(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, |node| node.first_child())
  }

  pub(crate) fn last_child(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, |node| node.last_child())
  }

  pub(crate) fn next_sibling(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, |node| node.next_sibling())
  }
  pub(crate) fn prev_sibling(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, Node::previous_sibling)
  }

  pub(crate) fn previous_sibling(self, tree: &WidgetTree) -> Option<WidgetId> {
    self.node_feature(tree, |node| node.previous_sibling())
  }

  #[allow(unused)]
  pub(crate) fn ancestor_of(self, other: WidgetId, tree: &WidgetTree) -> bool {
    other.ancestors(tree).any(|p| self == p)
  }

  pub(crate) fn ancestors(self, tree: &WidgetTree) -> impl Iterator<Item = WidgetId> + '_ {
    // `IndexTree` not check if is a freed id when create iterator, we may iterate
    // another node,so we need check it manually.
    assert!(!self.is_dropped(tree));

    let mut ancestors = self
      .0
      .ancestors(&tree.arena)
      .map(WidgetId)
      .collect::<Vec<_>>();
    let mut tail = *ancestors.last().unwrap_or(&self);
    while let Some(parent) = tail.detached_parent(tree) {
      if ancestors.contains(&parent) {
        break;
      }
      ancestors.extend(parent.0.ancestors(&tree.arena).map(WidgetId));
      tail = *ancestors.last().unwrap_or(&tail);
    }

    ancestors.into_iter()
  }

  #[inline]
  pub(crate) fn children(
    self, tree: &WidgetTree,
  ) -> impl DoubleEndedIterator<Item = WidgetId> + '_ {
    // `IndexTree` not check if is a freed id when create iterator, we may iterate
    assert!(!self.is_dropped(tree));
    self.0.children(&tree.arena).map(WidgetId)
  }

  pub(crate) fn descendants(self, tree: &WidgetTree) -> impl Iterator<Item = WidgetId> + '_ {
    // another node,so we need check it manually.
    assert!(!self.is_dropped(tree));
    self.0.descendants(&tree.arena).map(WidgetId)
  }

  pub(crate) fn on_widget_mounted(self, tree: &WidgetTree) {
    tree
      .window()
      .add_delay_event(DelayEvent::Mounted(self));
  }

  pub(crate) fn on_mounted_subtree(self, tree: &WidgetTree) {
    self.descendants(tree).for_each(|w| {
      tree
        .window()
        .add_delay_event(DelayEvent::Mounted(w))
    });
  }

  /// Dispose the whole subtree of `id`, include `id` itself.
  pub(crate) fn dispose_subtree(self, tree: &mut WidgetTree) {
    if self.is_dropped(tree) {
      return;
    }
    tree.prepare_subtree_for_dispose(self, true);
    tree
      .window()
      .add_delay_event(DelayEvent::Disposed(self));
  }

  pub(crate) fn insert_after(self, next: WidgetId, tree: &mut WidgetTree) {
    tree.clear_detached_parent(self);
    self.0.insert_after(next.0, &mut tree.arena);
  }

  pub(crate) fn insert_before(self, prev: WidgetId, tree: &mut WidgetTree) {
    tree.clear_detached_parent(self);
    self.0.insert_before(prev.0, &mut tree.arena);
  }

  pub(crate) fn append(self, child: WidgetId, tree: &mut WidgetTree) {
    tree.clear_detached_parent(child);
    self.0.append(child.0, &mut tree.arena);
  }

  /// Traverses to the leaf widget in the widget tree, returning it. Panics if
  /// there is more than one child in the path.
  pub(crate) fn single_leaf(self, tree: &WidgetTree) -> WidgetId {
    let mut leaf = self;
    while let Some(child) = leaf.single_child(tree) {
      leaf = child;
    }
    leaf
  }
  /// Return the single child of `widget`, panic if have more than once child.
  #[track_caller]
  pub(crate) fn single_child(&self, tree: &WidgetTree) -> Option<WidgetId> {
    assert_eq!(self.first_child(tree), self.last_child(tree), "Have more than one child.");
    self.first_child(tree)
  }

  fn node_feature(
    self, tree: &WidgetTree, method: impl FnOnce(&Node<Box<dyn RenderQueryable>>) -> Option<NodeId>,
  ) -> Option<WidgetId> {
    tree
      .arena
      .get(self.0)
      .and_then(method)
      .map(WidgetId)
  }

  pub(crate) fn assert_get<'a, 'b>(self, tree: &'a WidgetTree) -> &'a (dyn RenderQueryable + 'b) {
    self
      .get(tree)
      .expect("Widget not exists in the `tree`")
  }

  /// We assume the `f` wrap the widget into a new widget, and keep the old
  /// widget as part of the new widget, otherwise, undefined behavior.
  pub(crate) fn wrap_node(
    self, tree: &mut WidgetTree,
    f: impl FnOnce(Box<dyn RenderQueryable>) -> Box<dyn RenderQueryable>,
  ) {
    let node = self.get_node_mut(tree).unwrap();
    unsafe {
      let data = Box::from_raw(&mut **node as *mut _);
      let copied = std::mem::replace(node, f(data));
      std::mem::forget(copied)
    }
  }

  pub(crate) fn attach_data(self, data: Box<dyn Query>, tree: &mut WidgetTree) {
    self.wrap_node(tree, |node| Box::new(DataAttacher::new(node, data)));
  }

  pub(crate) fn attach_anonymous_data(self, data: impl Any, tree: &mut WidgetTree) {
    self.wrap_node(tree, |render| Box::new(AnonymousAttacher::new(render, Box::new(data))));
  }

  pub(crate) fn paint_subtree(self, tree: &WidgetTree, painter: &mut Painter) {
    let mut ctx = PaintingCtx::new(self, tree, painter);
    let mut painting = vec![];
    loop {
      let id = ctx.id();
      if !ctx.painter().is_transparent()
        && let Some(layout_box) = ctx.box_rect()
      {
        painting.push(id);
        let render = id.assert_get(tree);
        ctx
          .painter()
          .save()
          .translate(layout_box.min_x(), layout_box.min_y());
        render.paint(&mut ctx);

        if let Some(c) = id.first_child(tree) {
          ctx.switch_to(c);
          continue;
        }
      }

      while let Some(painting) = painting.pop() {
        ctx.painter().restore();
        ctx.switch_to(painting);
        ctx.finish();

        if let Some(sibling) = painting.next_sibling(tree) {
          ctx.switch_to(sibling);
          break;
        }
      }

      if painting.is_empty() {
        break;
      }
    }
  }
}

pub(crate) fn new_node(
  arena: &mut Arena<Box<dyn RenderQueryable>>, node: Box<dyn RenderQueryable>,
) -> WidgetId {
  WidgetId(arena.new_node(node))
}

impl WidgetId {
  /// Return a iterator of all reference of type `T` in this node.
  pub(crate) fn query_all_iter<T: Any>(
    self, tree: &WidgetTree,
  ) -> impl DoubleEndedIterator<Item = QueryRef<'_, T>> {
    let mut out = smallvec![];
    self
      .assert_get(tree)
      .query_all(&QueryId::of::<T>(), &mut out);
    out.into_iter().filter_map(QueryHandle::into_ref)
  }

  #[allow(unused)]
  pub(crate) fn query_all_write_iter<T: Any>(
    self, tree: &WidgetTree,
  ) -> impl DoubleEndedIterator<Item = WriteRef<'_, T>> {
    let mut out = smallvec![];
    self
      .assert_get(tree)
      .query_all_write(&QueryId::of::<T>(), &mut out);
    out.into_iter().filter_map(QueryHandle::into_mut)
  }

  #[allow(unused)]
  /// Query the outermost of reference of type `T` in this node.
  pub(crate) fn query_write<T: Any>(self, tree: &WidgetTree) -> Option<WriteRef<'_, T>> {
    self
      .assert_get(tree)
      .query_write(&QueryId::of::<T>())
      .and_then(QueryHandle::into_mut)
  }

  /// Query the outermost of reference of type `T` in this node.
  pub(crate) fn query_ref<T: Any>(self, tree: &WidgetTree) -> Option<QueryRef<'_, T>> {
    self
      .assert_get(tree)
      .query(&QueryId::of::<T>())
      .and_then(QueryHandle::into_ref)
  }

  pub(crate) fn queryable(&self, tree: &WidgetTree) -> bool { self.assert_get(tree).queryable() }
}

impl PlaceHolder {
  pub(crate) fn replace(self, widget: WidgetId, tree: &mut WidgetTree) {
    match self {
      PlaceHolder::PrevSibling(prev) => prev.insert_after(widget, tree),
      PlaceHolder::NextSibling(next) => next.insert_before(widget, tree),
      PlaceHolder::Parent(parent) => parent.append(widget, tree),
    }
  }
}
