using UnityEngine;
using System.Collections;

public enum AIEnemyBehaviorState
{
    run_towards_player,
    stand_still,
    crouch_still,
    bounce_from_player_impact,
    dying_lol,
    run_left_really_fast,
    frozen,
}

public class BaseEnemy : BaseMans 
{
    //Can only attack this often
    public float AttackTimer;
    protected float fRemainingAttackTimer;

    //Shots fire in a group this large
    public int ShotsPerAttack = 1;
    private int iShotsRemainingInCurrentAttackBurst;
    private bool bInAttackMode;

    //Time between shots in a group, think machine gun burst fire
    public float TimerBetweenShots;
    private float fRemainingTimeBetweenShots;

    protected PlayerMovement playerScript;

    public AIEnemyBehaviorState DefaultAI;
    public AIEnemyBehaviorState currentAiEnemyBehaviorState;

    //Can we move while attacking? Sometimes no!
    public bool CanRunAndAttack;

    public float fStunTimer;

    //Walking speed
    public float WalkingSpeedUnitsPerSecond = 4.0f;

    public float TurnDelay = 0.75f;
    protected float fTurnDelayTimer;


    public AudioClip died;

	// Use this for initialization
	protected override void Start () 
    {
	    base.Start();
        if( currentAiEnemyBehaviorState == 0 )  
    	    currentAiEnemyBehaviorState = DefaultAI;

	    died = Resources.Load<AudioClip>("sounds/enemy_killed");
    }
	
	// Update is called once per frame
	protected override void Update () 
    {
        base.Update();

	    switch (currentAiEnemyBehaviorState)
	    {
	        case AIEnemyBehaviorState.run_towards_player:
                AIBehavior_RunTowardsPlayer();
	            break;
            case AIEnemyBehaviorState.bounce_from_player_impact:
	            AIBehavior_BounceFromImpact();
	            break;
            case AIEnemyBehaviorState.stand_still:
                AIBehavior_StandStill();
	            break;
            case AIEnemyBehaviorState.run_left_really_fast:
                AIBehavior_RunLeftReallyFast();
	            break;
	    }
    }

    protected void HandleAttackRoutine()
    {
        if (projectile_BasicShot == null)
            return;

        if (bInAttackMode)
        {
            fRemainingTimeBetweenShots -= Time.smoothDeltaTime;
            if (fRemainingTimeBetweenShots <= 0.0f)
                FireProjectile();
        }
        else //if( ShouldAttack() )
        {
            fRemainingAttackTimer -= Time.smoothDeltaTime;
            if (fRemainingAttackTimer <= 0.0f)
                BeginAttack();
        }
    }



    public override void TakeDamage( float fDamageAmount )
    {
        if( currentAiEnemyBehaviorState != AIEnemyBehaviorState.dying_lol)
            base.TakeDamage( fDamageAmount );
    }

    public override void StartDying()
    {
        if (currentAiEnemyBehaviorState != AIEnemyBehaviorState.dying_lol)
        {
            if (playerScript != null || GetPlayerScript())
            {
                playerScript.iScore += (int) StartingHealth;
                myAudio.PlayOneShot(died);
            }

            if( Random.value <= 0.1f)
                SpawnPowerup();
        }

        myBody.fixedAngle = false;
        myBody.AddTorque( Random.value * 200.0f);
        myBody.AddForce( Vector2.up * (600.0f + Random.value * 600.0f));
        gameObject.layer = LayerMask.NameToLayer("NoCollide");
        currentAiEnemyBehaviorState = AIEnemyBehaviorState.dying_lol;
        

    }

    public void BeginAttack()
    {
        fRemainingAttackTimer = AttackTimer * 0.8f + (AttackTimer * 0.4f * Random.value);
        iShotsRemainingInCurrentAttackBurst = ShotsPerAttack;
        bInAttackMode = true;
        FireProjectile();
    }

    public override void FireProjectile()
    {
        base.FireProjectile();

        iShotsRemainingInCurrentAttackBurst--;
        if (iShotsRemainingInCurrentAttackBurst == 0)
            bInAttackMode = false;
        else
        {
            fRemainingTimeBetweenShots = TimerBetweenShots;
        }
    }

    protected virtual bool GetPlayerScript()
    {
        GameObject go = GameObject.Find("PlayerMans");
        if (go != null)
        {
            playerScript = go.GetComponent<PlayerMovement>();
        }

        return playerScript != null;
    }

    protected virtual void AIBehavior_RunTowardsPlayer()
    {
        if (playerScript == null && !GetPlayerScript())
            return;

        //tick down turn delay
        if (fTurnDelayTimer > 0.0f)
            fTurnDelayTimer -= Time.smoothDeltaTime;

        //if the player is too far, don't advance
        float fDirection = playerScript.transform.position.x - transform.position.x;

        if (Mathf.Abs(fDirection) >= 16.0f)
            return;

        bool bOldFacing = bFacingRight;

        //move towards the player
        float fDelta = bOldFacing ? 1.0f : -1.0f;
        
        if( fTurnDelayTimer <= 0.0f )
            fDelta = fDirection > 0 ? 1.0f : -1.0f;

        fDelta *= WalkingSpeedUnitsPerSecond * Time.smoothDeltaTime;
        if (fDelta < 0.0f)
            bFacingRight = false;
        else if (fDelta > 0.0f)
            bFacingRight = true;

        Vector3 vPos = transform.position;
        vPos.x += fDelta;
        transform.position = vPos;

        if (bOldFacing != bFacingRight)
        {
            ToggleFacing();
            fTurnDelayTimer = (TurnDelay * 0.8f) + (TurnDelay * 0.4f * Random.value);
        }

        HandleAttackRoutine();
    }

    void AIBehavior_StandStill()
    {
        if (playerScript == null && !GetPlayerScript())
            return;

        //tick down turn delay
        if (fTurnDelayTimer > 0.0f)
            fTurnDelayTimer -= Time.smoothDeltaTime;

        //if the player is too far, don't advance
        float fDirection = playerScript.transform.position.x - transform.position.x;

        if (Mathf.Abs(fDirection) >= 16.0f)
            return;

        bool bOldFacing = bFacingRight;

        //move towards the player
        float fDelta = 0.0f;

        if (fTurnDelayTimer <= 0.0f)
            fDelta = fDirection > 0 ? 1.0f : -1.0f;

        if (fDelta < 0.0f)
            bFacingRight = false;
        else if (fDelta > 0.0f)
            bFacingRight = true;


        if (bOldFacing != bFacingRight)
        {
            ToggleFacing();
            fTurnDelayTimer = (TurnDelay * 0.8f) + (TurnDelay * 0.4f * Random.value);
        }

        HandleAttackRoutine();
    }

    void AIBehavior_RunLeftReallyFast()
    {
        if (playerScript == null && !GetPlayerScript())
            return;

        //tick down turn delay
        if (fTurnDelayTimer > 0.0f)
            fTurnDelayTimer -= Time.smoothDeltaTime;

        //if the player is too far, don't advance
        float fDirection = playerScript.transform.position.x - transform.position.x;

        if (Mathf.Abs(fDirection) >= 16.0f)
            return;

        bool bOldFacing = bFacingRight;
        bFacingRight = false;

        //move left!
        float fDelta = WalkingSpeedUnitsPerSecond * Time.smoothDeltaTime * -1.0f;

        Vector3 vPos = transform.position;
        vPos.x += fDelta;
        transform.position = vPos;

        if (bOldFacing != bFacingRight)
        {
            ToggleFacing();
            fTurnDelayTimer = (TurnDelay * 0.8f) + (TurnDelay * 0.4f * Random.value);
        }

        HandleAttackRoutine();
    }


    void OnCollision2D()
    {
        
    }

    public override void FixedUpdate()
    {
        UpdateGrounded();
    }

    public void SuggestJump()
    {
        //If I am jumping, don't jump again.
        if (iJumpCounter > 0)
            return;

        //if I'm moving towards the player, sure.
        if (currentAiEnemyBehaviorState == AIEnemyBehaviorState.run_towards_player)
        {
            StartJump();    
        }
    }

    public void StartJump()
    {
        iJumpCounter++;
        myBody.AddForce(new Vector2(0, JumpForce));
    }

    void AIBehavior_BounceFromImpact()
    {
        fStunTimer -= Time.smoothDeltaTime;
        if (fStunTimer < 0.0f)
            currentAiEnemyBehaviorState = DefaultAI;
    }

    public override void OnCollisionEnter2D(Collision2D coll)
    {
        //did we hit the player?
        if ( playerScript != null && coll.gameObject == playerScript.gameObject)
        {
            //damage the player if we do that

            //bounce away if we do that
            fStunTimer = 0.5f;
            float fDirection = playerScript.transform.position.x - transform.position.x;
            float fDelta = fDirection < 0 ? 1.0f : -1.0f;

            Rigidbody2D myBody = GetComponent<Rigidbody2D>();
            myBody.AddForce( new Vector2(fDelta, 1.0f) * 600.0f );

            currentAiEnemyBehaviorState = AIEnemyBehaviorState.bounce_from_player_impact;
        }
    }

    public virtual void SpawnPowerup()
    {
        float fRando = Random.value;

        GameObject pup = null;
        if (fRando >= 0.5f)
            pup = Resources.Load<GameObject>("Prefabs/Powerup_Health");
        else
            pup = Resources.Load<GameObject>("Prefabs/Powerup_Ethics");

        GameObject newPup = Instantiate(pup);
        newPup.transform.position = transform.position;
    }

}
