using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = "Major Project/Pick Ups/HookShot Block")]
[System.Serializable]
public class HookShot : LogicBlock
{
    [SerializeField]
    [Header("Direction to shoot in")]
    private Direction Direction;

    [SerializeField]
    private string ResourceName;

    [SerializeField]
    private float ShotSpeed = 1;

    public override Block GetEndBlock(Block startBlock, Transform transform, LayerMask layerMask)
    {
        //setting up variables
        Vector3 position; // position wanted
        Block hit; //output of block detection
        Block retVal = startBlock; //block we'll actually move to

        //Check blocks in front until we hit an obstruction or went the distance
        for (int i = 1; i <= 30; i++)
        {
            //Next position to MoveTo
            position = startBlock.position + (Direction.ToVector(transform) * i);

            //if position is off the screen there is nothing to hit
            if (!Block.isPositionVisible(position))
                return startBlock;

            //if hit player return block they are standing on
            if (Block.isBlockAtPosition(position, 1, layerMask, out hit)) {
                if (hit.CurrentPlayer != null)
                    return hit;
            }

            //if block block paths return block infront of it
            if (Block.isBlockAtPosition(position + Vector3.up,1,layerMask))
            {
                return Block.GetOrCreateBlockAtPosition(position - Direction.ToVector(transform), 1, layerMask);
            }

        }

        return retVal;




    }

    protected override IEnumerator BlockLogic(Character player, float animationTime, bool useBlockDirection = false)
    {
        Block hitBlock = GetEndBlock(player.CurrentBlock, player.transform, ~player.Ignore);
        //Debug.Log("hookshot: " + hitBlock.position, hitBlock.gameObject);

        if (hitBlock == player.CurrentBlock)
            yield break;

        //Debug.Log("Instantiating shot");
        GameObject shot = GameObject.CreatePrimitive(PrimitiveType.Sphere);
        shot.transform.localScale = Vector3.one * 0.33f;
        yield return player.StartCoroutine(lerpShot(shot.transform, player.transform.position, hitBlock.VisualPosition,ShotSpeed));
        Destroy(shot);

        if (hitBlock.CurrentPlayer != null)
        {
            Block pullBlock = Block.GetOrCreateBlockAtPosition(player.CurrentBlock.position + Direction.ToVector(player.transform), 1, ~player.Ignore);
            yield return player.StartCoroutine(hitBlock.CurrentPlayer.MoveToBlock(pullBlock, Character.Animation.Hit, ShotSpeed));
        }
        else
        {
            yield return player.StartCoroutine(player.MoveToBlock(hitBlock, Character.Animation.Jump, ShotSpeed));
        }
    }

    private IEnumerator lerpShot(Transform target, Vector3 startPosition,Vector3 endPosition, float time)
    {

        float elapsedTime = 0;

        while (elapsedTime < time)
        {
            target.transform.position = Vector3.Lerp(startPosition, endPosition, elapsedTime / time);

            yield return new WaitForEndOfFrame();
            elapsedTime += Time.deltaTime;
        }

        target.position = endPosition;
    }

    public override void CopyToken(BlockToken token)
    {
        base.CopyToken(token);
        Direction = ((HookShotToken)token).Direction;
        ResourceName = ((HookShotToken)token).ResourceName;
        ShotSpeed = ((HookShotToken)token).ShotSpeed;
    }

    public override BlockToken ToToken(BlockToken token = null)
    {
        if (token == null)
            token = new HookShotToken(this);

        HookShotToken retVal = (HookShotToken)base.ToToken(token);
        retVal.Direction = Direction;
        retVal.ResourceName = ResourceName;
        retVal.ShotSpeed = ShotSpeed;

        return retVal;
    }

}

[System.Serializable]
public class HookShotToken : BlockToken
{
    public Direction Direction;
    public string ResourceName;
    public float ShotSpeed;

    public HookShotToken(LogicBlock block) : base(block) { }
}