using Framework.Entities;
using Framework.ItemSystem;
using Framework.PlasmaStateSystem;
using Framework.StatSystem;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Framework.StatSystem
{
    public static partial class StatType
    {
        public static readonly Id UseSpeed = Allocate();
    }
}

namespace Framework.ActorComponents
{
    public class ItemEquippedToSlot : CoreAction
    {
        public GameObject itemGameObject;

        public ItemEquippedToSlot(CoreBehaviour sender, GameObject itemGameObject)
            : base(sender)
        {
            this.itemGameObject = itemGameObject;
        }
    }

    public class Equip : Spark { }
    public class Unequip : Spark { }
    public class ForceEmpty : Spark { }
    public class ReleaseForceEmpty : Spark { }
    public class Use : Spark { }
    public class EndUse : Spark { }

    /// <summary>
    /// This component is used to attach an item object to a 
    /// specific bone (or transform) on this gameObject. The implementation
    /// provides state for using the item but in fact this slot should 
    /// be a inert. Create new implementations for specific functionality 
    /// such as left hand, right hand etc.
    /// </summary>
    [AddComponentMenu("Scripts/Framework/Actor Components/Item Slot")]
    public class ItemSlot : CoreBehaviour
    {
        // Inspector properties
        public Transform bone; // The bone transform to attach the object to
        public GameObject itemGameObject; // The gameObject of the item to attach

        // Private properties
        private Itemlike itemToEquip; // The item object that will be equipped

        // Stats

        // States
        private State main; // The parent state of all other states on this component

        private State empty; // The state of being empty (not holding an item)

        private State forcedEmpty; // Used for duel weilding by forcing this slot to be empty
        
        private State holding; // The state of holding an item
            // Not needed for this implementation
        private State idle; 
        private State usingItem;

        /// <summary>
        /// Called when this component is awoken after the Unity
        /// Awake is called. 
        /// </summary>
        protected override void InnerAwake()
        {
            // If the bone is null set the transform that it uses to be this components root transform
            if (this.bone == null)
            {
                this.bone = this.transform;
            }

            // Setup action handlers 
            AddActionHandler<EquipItemInput>(EquipItem);
            AddActionHandler<UnequipItemInput>(UnequipItem);

            // Setup states
            // Main state 
            this.main = new State("Main");

            // Empty states
            this.empty = new State("Empty", this.main, EnterEmpty, null, null);

            this.forcedEmpty = new State("Forced Empty", this.main);

            // Holding states
            this.holding = new State("Holding", this.main, EnterHolding, UpdateHolding, null);
            this.idle = new State("Idle", this.holding);
            this.usingItem = new State("Using Item", this.holding);
            this.holding.SetInitialStates(this.idle);

            this.main.SetInitialStates(this.empty);

            // Setup transitions 
            this.empty.SetTransition<Equip>(this.holding);
            this.holding.SetTransition<Unequip>(this.empty);
            this.main.SetTransition<ForceEmpty>(this.forcedEmpty);
            this.forcedEmpty.SetTransition<ReleaseForceEmpty>(this.empty);
            this.idle.SetTransition<Use>(this.usingItem);
            this.usingItem.SetTransition<EndUse>(this.idle);

            this.stateMachine = new StateMachine();
            this.stateMachine.SetInitialState(this.main);
        }

        /// <summary>
        /// Handles the <see cref="EquipItemInput"/> action by setting up the
        /// item to be equipped, igniting the unequip spark and then the 
        /// equip spark.
        /// </summary>
        /// <param name="action">The action.</param>
        private void EquipItem(EquipItemInput action)
        {
            this.itemToEquip = action.GetItem();
            this.stateMachine.Ignite(new Unequip());
            this.stateMachine.Ignite(new Equip());
        }

        /// <summary>
        /// Handles the <see cref="UnequipItemInput"/> action by setting 
        /// igniting the unequip spark.
        /// </summary>
        /// <param name="action">The action.</param>
        private void UnequipItem(UnequipItemInput action)
        {
            this.stateMachine.Ignite(new Unequip());
        }

        /// <summary>
        /// Called when the holding state is entered.
        /// </summary>
        private void EnterHolding()
        {
            this.itemGameObject = (GameObject)GameObject.Instantiate(Resources.Load(this.itemToEquip.GetName()), this.transform.position, new Quaternion());
            this.itemGameObject.transform.parent = this.bone;
            this.itemGameObject.transform.position = this.bone.position;
            this.itemGameObject.transform.rotation = this.bone.rotation;
            DirectInteract(itemGameObject, new SetupItemProperties(this, this.itemToEquip, this));
            this.itemToEquip = null;
            SelfInteract(new ItemEquippedToSlot(this, this.itemGameObject));
        }

        /// <summary>
        /// Called when the empty state is entered.
        /// </summary>
        private void EnterEmpty()
        {
            Destroy(this.itemGameObject);
        }

        /// <summary>
        /// Called when the holding state is udpated.
        /// </summary>
        private void UpdateHolding()
        {
            //if(this.itemGameObject != null)
            //{
            //    this.itemGameObject.transform.position = this.bone.position;
            //    this.itemGameObject.transform.rotation = this.bone.rotation;
            //}
        }
    }
}
