/// <summary>
        /// Finds or creates a node, notice that this will not perform an analysis on the node, which must be explicitly called on the node
        /// </summary>
        /// <param name="item">The asset item to find or create</param>
        /// <param name="compilationContext">The context in which the asset is compiled.</param>
        /// <returns>The build node associated with item</returns>
        public BuildAssetNode FindOrCreateNode([NotNull] AssetItem item, [NotNull] Type compilationContext)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }
            if (compilationContext == null)
            {
                throw new ArgumentNullException(nameof(compilationContext));
            }

            var nodeDesc = new BuildNodeDesc(item.Id, compilationContext);

            BuildAssetNode node;

            if (!nodes.TryGetValue(nodeDesc, out node))
            {
                node = new BuildAssetNode(item, compilationContext, this);
                nodes.TryAdd(nodeDesc, node);
            }
            else if (!ReferenceEquals(node.AssetItem, item))
            {
                node            = new BuildAssetNode(item, compilationContext, this);
                nodes[nodeDesc] = node;
            }

            return(node);
        }
        // TODO: this should be reimplemented at the service level (that consumes the build graph - thumbnails, preview, scene editors...)
        //private static void AnalyzeNode([NotNull] BuildAssetNode node, [NotNull] AssetCompilerContext context)
        //{
        //    if (node == null) throw new ArgumentNullException(nameof(node));
        //    if (context == null) throw new ArgumentNullException(nameof(context));
        //    node.Analyze(context);
        //    foreach (var reference in node.References)
        //    {
        //        AnalyzeNode(reference.Target, context);
        //    }
        //}

        //public void AssetChanged(AssetItem sender)
        //{
        //    //var node = FindOrCreateNode(sender, typeof(AssetCompilationContext)); // update only runtime ones ( as they are root )
        //    //var context = new AssetCompilerContext { CompilationContext = typeof(AssetCompilationContext) };
        //    //AnalyzeNode(node, context);
        //}

        /// <summary>
        /// Finds a node, notice that this will not perform an analysis on the node, which must be explicitly called on the node
        /// </summary>
        /// <param name="item">The asset item to find</param>
        /// <param name="compilationContext">The context in which the asset is compiled.</param>
        /// <returns>The build node associated with item or null if it was not found</returns>
        public BuildAssetNode FindNode([NotNull] AssetItem item, [NotNull] Type compilationContext)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }
            if (compilationContext == null)
            {
                throw new ArgumentNullException(nameof(compilationContext));
            }

            var nodeDesc = new BuildNodeDesc(item.Id, compilationContext);

            if (!nodes.TryGetValue(nodeDesc, out var node))
            {
                return(null);
            }

            if (!ReferenceEquals(node.AssetItem, item))
            {
                nodes.TryRemove(nodeDesc, out node);
                return(null);
            }

            return(node);
        }
        /// <summary>
        /// Removes the node from the build graph
        /// </summary>
        /// <param name="node">The node to remove</param>
        public void RemoveNode([NotNull] BuildAssetNode node)
        {
            if (node == null)
            {
                throw new ArgumentNullException(nameof(node));
            }
            var nodeDesc = new BuildNodeDesc(node.AssetItem.Id, node.CompilationContext);

            nodes.TryRemove(nodeDesc, out node);
        }
        /// <summary>
        /// Removes the nodes associated with item from the build graph
        /// </summary>
        /// <param name="item">The item to use to find nodes to remove</param>
        public void RemoveNode([NotNull] AssetItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException(nameof(item));
            }
            var assetNodes = FindNodes(item).ToList();

            foreach (var buildAssetNode in assetNodes)
            {
                var nodeDesc = new BuildNodeDesc(item.Id, buildAssetNode.CompilationContext);
                nodes.TryRemove(nodeDesc, out _);
            }
        }