
using System;
using System.Linq;
using Sandbox;
using Sandbox.ActionGraphs;

namespace Editor.ActionGraphs;

partial class ActionGraphView
{
	public override void CleanUp()
	{
		var changed = false;

		changed |= FixSceneReferences();

		if ( changed )
		{
			Log.Info( $"Finished clean up" );

			RebuildFromGraph();
			Save();
		}
		else
		{
			Log.Info( $"Nothing to clean up!" );
		}
	}

	private bool FixSceneReferences()
	{
		var constNodes = ActionGraph.Nodes.Values
			.Where( x => x.Definition == EditorNodeLibrary.Constant )
			.Where( x => x.Properties.Value.Value is Component or GameObject or Resource )
			.ToArray();

		if ( constNodes.Length == 0 )
		{
			return false;
		}

		Log.Info( $"Replacing {constNodes.Length} invalid references..." );

		var links = constNodes
			.SelectMany( x => x.Outputs.Result.Links )
			.ToArray();

		var replacements = constNodes.ToDictionary( x => x, x =>
		{
			if ( x.Properties.Value.Value is Resource resource )
			{
				var resourceRef = ActionGraph.AddNode( EditorNodeLibrary.Get( "resource.ref" )!, x.Parent );

				resourceRef.Properties["T"].Value = resource.GetType();
				resourceRef.Properties["value"].Value = resource;

				return resourceRef;
			}

			var sceneRef = ActionGraph.AddNode( EditorNodeLibrary.Get( "scene.ref" )!, x.Parent );
			var properties = x.Properties.Value.Value switch
			{
				Component comp => SceneReferenceHelper.GetNodeProperties( comp ),
				GameObject go => SceneReferenceHelper.GetNodeProperties( go ),
				_ => throw new NotImplementedException()
			};

			foreach ( var property in properties )
			{
				sceneRef.Properties[property.Key].Value = property.Value;
			}

			return sceneRef;
		} );

		foreach ( var link in links )
		{
			var newSource = replacements[link.Source.Node].Outputs.Result;

			if ( link.IsArrayElement )
			{
				link.Target.SetLink( newSource, link.ArrayIndex );
			}
			else
			{
				link.Target.SetLink( newSource );
			}
		}

		foreach ( var oldNode in constNodes )
		{
			oldNode.Remove();
		}

		return true;
	}
}
