use std::{
    any::TypeId,
    ops::{
        Deref,
        DerefMut,
    },
    sync::Arc,
};
use rustc_hash::{
    FxHashMap,
    FxHashSet,
};
use shipyard::{
    error::GetStorage,
    track::Untracked,
    Component,
    Get,
    IntoBorrow,
    ScheduledWorkload,
    SystemModificator,
    Unique,
    View,
    ViewMut,
    Workload,
    World,
};
use crate::{
    events::EventName,
    node::{
        ElementNode,
        FromAnyValue,
        NodeType,
        OwnedAttributeValue,
    },
    node_ref::{
        NodeMask,
        NodeMaskBuilder,
    },
    passes::{
        Dependant,
        DirtyNodeStates,
        PassDirection,
        TypeErasedState,
    },
    prelude::{
        AttributeMaskBuilder,
        AttributeName,
    },
    tags::TagName,
    tree::{
        TreeMut,
        TreeMutView,
        TreeRef,
        TreeRefView,
    },
    FxDashSet,
    NodeId,
    SendAnyMap,
};
#[derive(Unique)]
pub(crate) struct SendAnyMapWrapper(SendAnyMap);
impl Deref for SendAnyMapWrapper {
    type Target = SendAnyMap;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
#[derive(Unique, Default)]
pub(crate) struct DirtyNodesResult(FxDashSet<NodeId>);
impl Deref for DirtyNodesResult {
    type Target = FxDashSet<NodeId>;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
pub(crate) struct NodesDirty<V: FromAnyValue + Send + Sync> {
    passes_updated: FxHashMap<NodeId, FxHashSet<TypeId>>,
    nodes_updated: FxHashMap<NodeId, NodeMask>,
    nodes_created: FxHashSet<NodeId>,
    pub(crate) passes: Box<[TypeErasedState<V>]>,
}
impl<V: FromAnyValue + Send + Sync> NodesDirty<V> {
    fn mark_dirty(&mut self, node_id: NodeId, mask: NodeMask) {
        self.passes_updated.entry(node_id).or_default().extend(
            self.passes
                .iter()
                .filter_map(|x| x.mask.overlaps(&mask).then_some(x.this_type_id)),
        );
        let nodes_updated = &mut self.nodes_updated;
        if let Some(node) = nodes_updated.get_mut(&node_id) {
            *node = node.union(&mask);
        } else {
            nodes_updated.insert(node_id, mask);
        }
    }
    fn mark_parent_added_or_removed(&mut self, node_id: NodeId) {
        let hm = self.passes_updated.entry(node_id).or_default();
        for pass in &*self.passes {
            for &pass in &pass.parent_dependancies_ids {
                hm.insert(pass);
            }
        }
    }
    fn mark_child_changed(&mut self, node_id: NodeId) {
        let hm = self.passes_updated.entry(node_id).or_default();
        for pass in &*self.passes {
            for &pass in &pass.child_dependancies_ids {
                hm.insert(pass);
            }
        }
    }
}
pub struct RealDom<V: FromAnyValue + Send + Sync = ()> {
    pub(crate) world: World,
    nodes_listening: FxHashMap<EventName, FxHashSet<NodeId>>,
    pub(crate) dirty_nodes: NodesDirty<V>,
    workload: ScheduledWorkload,
    root_id: NodeId,
    phantom: std::marker::PhantomData<V>,
}
impl<V: FromAnyValue + Send + Sync> RealDom<V> {
    pub fn new(tracked_states: impl Into<Box<[TypeErasedState<V>]>>) -> RealDom<V> {
        let mut tracked_states = tracked_states.into();
        for i in 1..=tracked_states.len() {
            let (before, after) = tracked_states.split_at_mut(i);
            let (current, before) = before.split_last_mut().unwrap();
            for state in before.iter_mut().chain(after.iter_mut()) {
                let dependants = Arc::get_mut(&mut state.dependants).unwrap();
                let current_dependant = Dependant {
                    type_id: current.this_type_id,
                    enter_shadow_dom: current.enter_shadow_dom,
                };
                if current
                    .parent_dependancies_ids
                    .contains(&state.this_type_id)
                    && !dependants.child.contains(¤t_dependant)
                {
                    dependants.child.push(current_dependant);
                }
                if current.child_dependancies_ids.contains(&state.this_type_id)
                    && !dependants.parent.contains(¤t_dependant)
                {
                    dependants.parent.push(current_dependant);
                }
                if current.node_dependancies_ids.contains(&state.this_type_id)
                    && !dependants.node.contains(¤t.this_type_id)
                {
                    dependants.node.push(current.this_type_id);
                }
            }
            let dependants = Arc::get_mut(&mut current.dependants).unwrap();
            let current_dependant = Dependant {
                type_id: current.this_type_id,
                enter_shadow_dom: current.enter_shadow_dom,
            };
            match current.pass_direction {
                PassDirection::ChildToParent => {
                    if !dependants.parent.contains(¤t_dependant) {
                        dependants.parent.push(current_dependant);
                    }
                }
                PassDirection::ParentToChild => {
                    if !dependants.child.contains(¤t_dependant) {
                        dependants.child.push(current_dependant);
                    }
                }
                _ => {}
            }
        }
        let workload = construct_workload(&mut tracked_states);
        let (workload, _) = workload.build().unwrap();
        let mut world = World::new();
        let root_node: NodeType<V> = NodeType::Element(ElementNode {
            tag: TagName::Root,
            attributes: FxHashMap::default(),
            listeners: FxHashSet::default(),
        });
        let root_id = world.add_entity(root_node);
        {
            let mut tree: TreeMutView = world.borrow().unwrap();
            tree.create_node(root_id);
        }
        let mut passes_updated = FxHashMap::default();
        let mut nodes_updated = FxHashMap::default();
        passes_updated.insert(
            root_id,
            tracked_states.iter().map(|x| x.this_type_id).collect(),
        );
        nodes_updated.insert(root_id, NodeMaskBuilder::ALL.build());
        RealDom {
            world,
            nodes_listening: FxHashMap::default(),
            dirty_nodes: NodesDirty {
                passes_updated,
                nodes_updated,
                passes: tracked_states,
                nodes_created: [root_id].into_iter().collect(),
            },
            workload,
            root_id,
            phantom: std::marker::PhantomData,
        }
    }
    pub fn tree_ref(&self) -> TreeRefView {
        self.world.borrow().unwrap()
    }
    pub fn tree_mut(&self) -> TreeMutView {
        self.world.borrow().unwrap()
    }
    pub fn create_node(&mut self, node: impl Into<NodeType<V>>) -> NodeMut<'_, V> {
        let node = node.into();
        let id = self.world.add_entity(node);
        self.tree_mut().create_node(id);
        self.dirty_nodes
            .passes_updated
            .entry(id)
            .or_default()
            .extend(self.dirty_nodes.passes.iter().map(|x| x.this_type_id));
        self.dirty_nodes
            .mark_dirty(id, NodeMaskBuilder::ALL.build());
        self.dirty_nodes.nodes_created.insert(id);
        NodeMut::new(id, self)
    }
    pub fn is_node_listening(&self, node_id: &NodeId, event: &EventName) -> bool {
        self.nodes_listening
            .get(event)
            .map(|listeners| listeners.contains(node_id))
            .unwrap_or_default()
    }
    pub fn get_listeners(&self, event: &EventName) -> Vec<NodeRef<V>> {
        if let Some(nodes) = self.nodes_listening.get(event) {
            nodes
                .iter()
                .map(|id| NodeRef { id: *id, dom: self })
                .collect()
        } else {
            Vec::new()
        }
    }
    pub fn root_id(&self) -> NodeId {
        self.root_id
    }
    pub fn contains(&self, id: NodeId) -> bool {
        self.tree_ref().contains(id)
    }
    pub fn get(&self, id: NodeId) -> Option<NodeRef<'_, V>> {
        self.contains(id).then_some(NodeRef { id, dom: self })
    }
    pub fn get_mut(&mut self, id: NodeId) -> Option<NodeMut<'_, V>> {
        let contains = self.contains(id);
        contains.then(|| NodeMut::new(id, self))
    }
    fn borrow_raw<'a, B: IntoBorrow>(&'a self) -> Result<B, GetStorage>
    where
        B::Borrow: shipyard::Borrow<'a, View = B>,
    {
        self.world.borrow()
    }
    fn borrow_node_type_mut(&self) -> Result<ViewMut<NodeType<V>>, GetStorage> {
        self.world.borrow()
    }
    pub fn update_state(
        &mut self,
        ctx: SendAnyMap,
    ) -> (FxDashSet<NodeId>, FxHashMap<NodeId, NodeMask>) {
        let passes = std::mem::take(&mut self.dirty_nodes.passes_updated);
        let nodes_updated = std::mem::take(&mut self.dirty_nodes.nodes_updated);
        let dirty_nodes =
            DirtyNodeStates::with_passes(self.dirty_nodes.passes.iter().map(|p| p.this_type_id));
        let tree = self.tree_ref();
        for (node_id, passes) in passes {
            if let Some(height) = tree.height(node_id) {
                for pass in passes {
                    dirty_nodes.insert(pass, node_id, height);
                }
            }
        }
        let _ = self.world.remove_unique::<DirtyNodeStates>();
        let _ = self.world.remove_unique::<SendAnyMapWrapper>();
        self.world.add_unique(dirty_nodes);
        self.world.add_unique(SendAnyMapWrapper(ctx));
        self.world.add_unique(DirtyNodesResult::default());
        self.workload.run_with_world(&self.world).unwrap();
        let dirty = self.world.remove_unique::<DirtyNodesResult>().unwrap();
        (dirty.0, nodes_updated)
    }
    pub fn traverse_depth_first_advanced(&self, mut f: impl FnMut(NodeRef<V>) -> bool) {
        let mut stack = vec![self.root_id()];
        let tree = self.tree_ref();
        while let Some(id) = stack.pop() {
            if let Some(node) = self.get(id) {
                let traverse_children = f(node);
                if traverse_children {
                    let children = tree.children_ids_advanced(id, false);
                    stack.extend(children.iter().copied().rev());
                }
            }
        }
    }
    pub fn traverse_depth_first(&self, mut f: impl FnMut(NodeRef<V>)) {
        self.traverse_depth_first_advanced(move |node| {
            f(node);
            true
        })
    }
    pub fn raw_world(&self) -> &World {
        &self.world
    }
    pub fn raw_world_mut(&mut self) -> &mut World {
        &mut self.world
    }
}
pub struct ViewEntry<'a, V: Component + Send + Sync> {
    view: View<'a, V>,
    id: NodeId,
}
impl<'a, V: Component + Send + Sync> ViewEntry<'a, V> {
    fn new(view: View<'a, V>, id: NodeId) -> Self {
        Self { view, id }
    }
}
impl<'a, V: Component + Send + Sync> Deref for ViewEntry<'a, V> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        &self.view[self.id]
    }
}
pub struct ViewEntryMut<'a, V: Component<Tracking = Untracked> + Send + Sync> {
    view: ViewMut<'a, V, Untracked>,
    id: NodeId,
}
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> ViewEntryMut<'a, V> {
    fn new(view: ViewMut<'a, V, Untracked>, id: NodeId) -> Self {
        Self { view, id }
    }
}
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> Deref for ViewEntryMut<'a, V> {
    type Target = V;
    fn deref(&self) -> &Self::Target {
        self.view.get(self.id).unwrap()
    }
}
impl<'a, V: Component<Tracking = Untracked> + Send + Sync> DerefMut for ViewEntryMut<'a, V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        (&mut self.view).get(self.id).unwrap()
    }
}
pub trait NodeImmutable<V: FromAnyValue + Send + Sync = ()>: Sized {
    fn real_dom(&self) -> &RealDom<V>;
    fn id(&self) -> NodeId;
    #[inline]
    fn node_type(&self) -> ViewEntry<NodeType<V>> {
        self.get().unwrap()
    }
    #[inline]
    fn get<'a, T: Component + Sync + Send>(&'a self) -> Option<ViewEntry<'a, T>> {
        let view: View<'a, T> = self.real_dom().borrow_raw().ok()?;
        view.contains(self.id())
            .then(|| ViewEntry::new(view, self.id()))
    }
    #[inline]
    fn children_ids_advanced(&self, id: NodeId, enter_shadow_dom: bool) -> Vec<NodeId> {
        self.real_dom()
            .tree_ref()
            .children_ids_advanced(id, enter_shadow_dom)
    }
    #[inline]
    fn child_ids(&self) -> Vec<NodeId> {
        self.real_dom().tree_ref().children_ids(self.id())
    }
    #[inline]
    fn children(&self) -> Vec<NodeRef<V>> {
        self.child_ids()
            .iter()
            .map(|id| NodeRef {
                id: *id,
                dom: self.real_dom(),
            })
            .collect()
    }
    #[inline]
    fn parent_id(&self) -> Option<NodeId> {
        self.real_dom().tree_ref().parent_id(self.id())
    }
    #[inline]
    fn parent(&self) -> Option<NodeRef<V>> {
        self.parent_id().map(|id| NodeRef {
            id,
            dom: self.real_dom(),
        })
    }
    #[inline]
    fn height(&self) -> u16 {
        self.real_dom().tree_ref().height(self.id()).unwrap()
    }
}
pub struct NodeRef<'a, V: FromAnyValue + Send + Sync = ()> {
    id: NodeId,
    dom: &'a RealDom<V>,
}
impl<'a, V: FromAnyValue + Send + Sync> Clone for NodeRef<'a, V> {
    fn clone(&self) -> Self {
        *self
    }
}
impl<'a, V: FromAnyValue + Send + Sync> Copy for NodeRef<'a, V> {}
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeRef<'a, V> {
    #[inline(always)]
    fn real_dom(&self) -> &RealDom<V> {
        self.dom
    }
    #[inline(always)]
    fn id(&self) -> NodeId {
        self.id
    }
}
pub struct NodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
    id: NodeId,
    dom: &'a mut RealDom<V>,
}
impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
    pub fn new(id: NodeId, dom: &'a mut RealDom<V>) -> Self {
        Self { id, dom }
    }
}
impl<'a, V: FromAnyValue + Send + Sync> NodeImmutable<V> for NodeMut<'a, V> {
    #[inline(always)]
    fn real_dom(&self) -> &RealDom<V> {
        self.dom
    }
    #[inline(always)]
    fn id(&self) -> NodeId {
        self.id
    }
}
impl<'a, V: FromAnyValue + Send + Sync> NodeMut<'a, V> {
    #[inline(always)]
    pub fn real_dom_mut(&mut self) -> &mut RealDom<V> {
        self.dom
    }
    #[inline]
    pub fn get_mut<T: Component<Tracking = Untracked> + Sync + Send>(
        &mut self,
    ) -> Option<ViewEntryMut<T>> {
        self.dom
            .dirty_nodes
            .passes_updated
            .entry(self.id)
            .or_default()
            .insert(TypeId::of::<T>());
        let view_mut: ViewMut<T> = self.dom.borrow_raw().ok()?;
        view_mut
            .contains(self.id)
            .then_some(ViewEntryMut::new(view_mut, self.id))
    }
    #[inline]
    pub fn insert<T: Component + Sync + Send>(&mut self, value: T) {
        self.dom
            .dirty_nodes
            .passes_updated
            .entry(self.id)
            .or_default()
            .insert(TypeId::of::<T>());
        self.dom.world.add_component(self.id, value);
    }
    #[inline]
    pub fn add_child(&mut self, child: NodeId) {
        self.dom.dirty_nodes.mark_child_changed(self.id);
        self.dom.dirty_nodes.mark_parent_added_or_removed(child);
        self.dom.tree_mut().add_child(self.id, child);
    }
    #[inline]
    pub fn insert_after(&mut self, old: NodeId) {
        let id = self.id();
        let parent_id = { self.dom.tree_ref().parent_id(old) };
        if let Some(parent_id) = parent_id {
            self.dom.dirty_nodes.mark_child_changed(parent_id);
            self.dom.dirty_nodes.mark_parent_added_or_removed(id);
        }
        self.dom.tree_mut().insert_after(old, id);
    }
    #[inline]
    pub fn insert_before(&mut self, old: NodeId) {
        let id = self.id();
        let parent_id = { self.dom.tree_ref().parent_id(old) };
        if let Some(parent_id) = parent_id {
            self.dom.dirty_nodes.mark_child_changed(parent_id);
            self.dom.dirty_nodes.mark_parent_added_or_removed(id);
        }
        self.dom.tree_mut().insert_before(old, id);
    }
    #[inline]
    pub fn remove(&mut self) {
        let id = self.id();
        {
            let RealDom {
                world,
                nodes_listening,
                ..
            } = &mut self.dom;
            let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
            if let NodeType::Element(ElementNode { listeners, .. }) = (&mut view).get(id).unwrap() {
                let listeners = std::mem::take(listeners);
                for event in listeners {
                    nodes_listening.get_mut(&event).unwrap().remove(&id);
                }
            }
        }
        let parent_id = { self.dom.tree_ref().parent_id(id) };
        if let Some(parent_id) = parent_id {
            self.real_dom_mut()
                .dirty_nodes
                .mark_child_changed(parent_id);
        }
        let children_ids = self.child_ids();
        for child in children_ids {
            self.dom.get_mut(child).unwrap().remove();
        }
        self.dom.tree_mut().remove(id);
        self.real_dom_mut().raw_world_mut().delete_entity(id);
    }
    #[inline]
    pub fn add_event_listener(&mut self, event: EventName) {
        let id = self.id();
        let RealDom {
            world,
            dirty_nodes,
            nodes_listening,
            ..
        } = &mut self.dom;
        let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
        if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
            listeners.insert(event);
            match nodes_listening.get_mut(&event) {
                Some(hs) => {
                    hs.insert(id);
                }
                None => {
                    let mut hs = FxHashSet::default();
                    hs.insert(id);
                    nodes_listening.insert(event, hs);
                }
            }
        }
    }
    #[inline]
    pub fn remove_event_listener(&mut self, event: &EventName) {
        let id = self.id();
        let RealDom {
            world,
            dirty_nodes,
            nodes_listening,
            ..
        } = &mut self.dom;
        let mut view: ViewMut<NodeType<V>> = world.borrow().unwrap();
        let node_type: &mut NodeType<V> = (&mut view).get(self.id).unwrap();
        if let NodeType::Element(ElementNode { listeners, .. }) = node_type {
            dirty_nodes.mark_dirty(self.id, NodeMaskBuilder::new().with_listeners().build());
            listeners.remove(event);
            nodes_listening.get_mut(event).unwrap().remove(&id);
        }
    }
    pub fn node_type_mut(&mut self) -> NodeTypeMut<'_, V> {
        let id = self.id();
        let RealDom {
            world, dirty_nodes, ..
        } = &mut self.dom;
        let view: ViewMut<NodeType<V>> = world.borrow().unwrap();
        let node_type = ViewEntryMut::new(view, id);
        match &*node_type {
            NodeType::Element(_) => NodeTypeMut::Element(ElementNodeMut {
                id,
                element: node_type,
                dirty_nodes,
            }),
            NodeType::Text(_) => NodeTypeMut::Text(TextNodeMut {
                id,
                text: node_type,
                dirty_nodes,
            }),
            NodeType::Placeholder => NodeTypeMut::Placeholder,
        }
    }
    pub fn set_type(&mut self, new: NodeType<V>) {
        {
            let mut view: ViewMut<NodeType<V>> = self.dom.borrow_node_type_mut().unwrap();
            *(&mut view).get(self.id).unwrap() = new;
        }
        self.dom
            .dirty_nodes
            .mark_dirty(self.id, NodeMaskBuilder::ALL.build())
    }
    #[inline]
    pub fn clone_node(&mut self) -> NodeId {
        let new_node = self.node_type().clone();
        let rdom = self.real_dom_mut();
        let new_id = rdom.create_node(new_node).id();
        let children = self.child_ids();
        let children = children.to_vec();
        let rdom = self.real_dom_mut();
        for child in children {
            let child_id = rdom.get_mut(child).unwrap().clone_node();
            rdom.get_mut(new_id).unwrap().add_child(child_id);
        }
        new_id
    }
}
pub enum NodeTypeMut<'a, V: FromAnyValue + Send + Sync = ()> {
    Element(ElementNodeMut<'a, V>),
    Text(TextNodeMut<'a, V>),
    Placeholder,
}
pub struct TextNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
    id: NodeId,
    text: ViewEntryMut<'a, NodeType<V>>,
    dirty_nodes: &'a mut NodesDirty<V>,
}
impl<V: FromAnyValue + Send + Sync> TextNodeMut<'_, V> {
    pub fn text(&self) -> &str {
        match &*self.text {
            NodeType::Text(text) => text,
            _ => unreachable!(),
        }
    }
    pub fn text_mut(&mut self) -> &mut String {
        self.dirty_nodes
            .mark_dirty(self.id, NodeMaskBuilder::new().with_text().build());
        match &mut *self.text {
            NodeType::Text(text) => text,
            _ => unreachable!(),
        }
    }
}
impl<V: FromAnyValue + Send + Sync> Deref for TextNodeMut<'_, V> {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        match &*self.text {
            NodeType::Text(text) => text,
            _ => unreachable!(),
        }
    }
}
impl<V: FromAnyValue + Send + Sync> DerefMut for TextNodeMut<'_, V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.text_mut()
    }
}
pub struct ElementNodeMut<'a, V: FromAnyValue + Send + Sync = ()> {
    id: NodeId,
    element: ViewEntryMut<'a, NodeType<V>>,
    dirty_nodes: &'a mut NodesDirty<V>,
}
impl std::fmt::Debug for ElementNodeMut<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ElementNodeMut")
            .field("id", &self.id)
            .field("element", &*self.element)
            .finish()
    }
}
impl<V: FromAnyValue + Send + Sync> ElementNodeMut<'_, V> {
    fn element_mut(&mut self) -> &mut ElementNode<V> {
        match &mut *self.element {
            NodeType::Element(element) => element,
            _ => unreachable!(),
        }
    }
    pub fn set_attribute(
        &mut self,
        name: impl Into<AttributeName>,
        value: impl Into<OwnedAttributeValue<V>>,
    ) -> Option<OwnedAttributeValue<V>> {
        let name = name.into();
        let value = value.into();
        self.dirty_nodes.mark_dirty(
            self.id,
            NodeMaskBuilder::new()
                .with_attrs(AttributeMaskBuilder::Some(&[name]))
                .build(),
        );
        self.element_mut().attributes.insert(name, value)
    }
    pub fn remove_attribute(&mut self, name: &AttributeName) -> Option<OwnedAttributeValue<V>> {
        self.dirty_nodes.mark_dirty(
            self.id,
            NodeMaskBuilder::new()
                .with_attrs(AttributeMaskBuilder::Some(&[*name]))
                .build(),
        );
        self.element_mut().attributes.remove(name)
    }
    pub fn get_attribute_mut(
        &mut self,
        name: &AttributeName,
    ) -> Option<&mut OwnedAttributeValue<V>> {
        self.dirty_nodes.mark_dirty(
            self.id,
            NodeMaskBuilder::new()
                .with_attrs(AttributeMaskBuilder::Some(&[*name]))
                .build(),
        );
        self.element_mut().attributes.get_mut(name)
    }
}
fn construct_workload<V: FromAnyValue + Send + Sync>(
    passes: &mut [TypeErasedState<V>],
) -> Workload {
    let mut workload = Workload::new("Main Workload");
    let mut unresloved_workloads = passes
        .iter_mut()
        .enumerate()
        .map(|(i, pass)| {
            let workload = Some(pass.create_workload());
            (i, pass, workload)
        })
        .collect::<Vec<_>>();
    for (id, _, workload) in &mut unresloved_workloads {
        *workload = Some(workload.take().unwrap().tag(id.to_string()));
    }
    for i in 0..unresloved_workloads.len() {
        let (_, pass, _) = &unresloved_workloads[i];
        let all_dependancies: Vec<_> = pass.combined_dependancy_type_ids().collect();
        for ty_id in all_dependancies {
            let &(dependancy_id, _, _) = unresloved_workloads
                .iter()
                .find(|(_, pass, _)| pass.this_type_id == ty_id)
                .unwrap();
            let (_, _, workload) = &mut unresloved_workloads[i];
            *workload = workload
                .take()
                .map(|workload| workload.after_all(dependancy_id.to_string()));
        }
    }
    for (_, _, mut workload_system) in unresloved_workloads {
        workload = workload.with_system(workload_system.take().unwrap());
    }
    workload
}