using Framework.Entities;
using Framework.GuardianSaveSystem;
using Framework.InteractionSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Framework.Extensions
{
    /// <summary>
    /// Provides extension methods for the UnityEngine.<see cref="GameObject"/> class.
    /// </summary>
    public static class GameObjectExtender
    {
        /// <summary>
        /// This method is used within the <see cref="InteractionSystem"/> namespace. It is
        /// used to request exposure to <see cref="Interactable"/> components from a behaviour.
        /// </summary>
        /// <param name="behaviour">The game object.</param>
        /// <param name="requester">The requester.</param>
        public static void RequestExpose(this GameObject gameObject, Interactable requester)
        {
            CoreBehaviour[] interactables = gameObject.GetComponents<CoreBehaviour>();
            for (int i = 0; i < interactables.Length; i++)
            {
                interactables[i].RequestExpose(requester);
            }
        }

        /// <summary>
        /// Sends an action to directly to a gameObject, interacting
        /// with only that gameObject.
        /// </summary>
        /// <param name="behaviour"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static bool Interact(this GameObject gameObject, Actionlike action)
        {
            int responseCount = 0;
            try
            {
                CoreBehaviour[] interactables = gameObject.GetComponents<CoreBehaviour>();
                for (int i = 0; i < interactables.Length; i++)
                {
                    if (interactables[i].Receive(action))
                    {
                        //Log(this + " acted " + action.GetType().Name + " upon " + this.exposedComponents[action.GetType()][i]);
                        responseCount++;
                    }
                }
            }
            catch (NullReferenceException)
            {
                Debug.LogError("gameObject: " + (gameObject != null));
                if (gameObject != null)
                {
                    Debug.LogError("coreBehaviour: " + (gameObject.GetComponents<CoreBehaviour>() != null));
                }
            }
            return responseCount > 0;
        }
		
		/// <summary>
        /// Recursively searches for a transform with the target name through the children 
		/// of the calling transform.
        /// </summary>
        /// <returns>The first found transform with the give name.</returns>
		public static Transform RecursivelyFindChild(this Transform transform, string targetName)
        {
            // check if the current bone is the bone we're looking for, if so return it
            if (transform.name == targetName)
                return transform;

            // search through child bones for the bone we're looking for
            for (int i = 0; i < transform.childCount; ++i)
            {
                // the recursive step; repeat the search one step deeper in the hierarchy
                Transform found = RecursivelyFindChild(transform.GetChild(i), targetName);

                // a transform was returned by the search above that is not null,
                // it must be the bone we're looking for
                if (found != null)
                    return found;
            }

            // bone with name was not found
            return null;
        }
    }
}
