// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language.Components;
using Microsoft.AspNetCore.Razor.Language.Intermediate;

namespace Microsoft.AspNetCore.Razor.Language.Extensions
{
	public sealed class FunctionsDirectivePass : IntermediateNodePassBase, IRazorDirectiveClassifierPass
	{
		protected override void ExecuteCore( RazorCodeDocument codeDocument, DocumentIntermediateNode documentNode )
		{
			var @class = documentNode.FindPrimaryClass();
			if ( @class == null )
			{
				return;
			}

			var directiveNodes = new List<IntermediateNodeReference>();
			directiveNodes.AddRange( documentNode.FindDirectiveReferences( FunctionsDirective.Directive ) );

			if ( FileKinds.IsComponent( codeDocument.GetFileKind() ) )
			{
				directiveNodes.AddRange( documentNode.FindDirectiveReferences( ComponentCodeDirective.Directive ) );
			}

			// Now we have all the directive nodes, we want to add them to the end of the class node in document order.
			var orderedDirectives = directiveNodes.OrderBy( n => n.Node.Source?.AbsoluteIndex );
			foreach ( var directiveReference in orderedDirectives )
			{
				var node = directiveReference.Node;
				for ( var i = 0; i < node.Children.Count; i++ )
				{
					@class.Children.Add( node.Children[i] );
				}

				// We don't want to keep the original directive node around anymore.
				// Otherwise this can cause unintended side effects in the subsequent passes.
				directiveReference.Remove();
			}
		}
	}
}
