using UnityEngine;
using System.Collections;

public enum Stance
{
    standing,
    crouching,
    MAX,
}

public class PlayerMovement : BaseMans
{
    private InputManager theInput;

    InputTypes dashDirection = InputTypes.NO_INPUT;

    public float WalkSpeed = 5.0f;
    public float DashSpeed = 8.0f;

    private bool bAmFloorDropping;

    public float fRemainingEthics = 100.0f;
    public float fFrustration;

    public float fDamageImmunityTimer;

    public MeshFilter frustrationLightningQuad;

    private float fTimeUntilNextLightning = 5.0f;
    private float fActiveLightningTimer = 0.8f;
    private BaseEnemy lightningTarget;


    //fedora power
    private bool bFedoraIsFlying;
    private float fFedoraChargePercentage;

    public GameObject fedoraReadyGameObject;

    public GameObject actualFrostdora;

    private float fRecentEthicsChangeTimer;
    private bool bEthicsChangeWasPositive;

    public int iScore;

    public GameObject prefab_particleHealed;


    public AudioClip playerJump;
    public AudioClip playerLand;
    public AudioClip playerLightning;
    public AudioClip playerEthicsDown;
    public AudioClip playerEthicsUp;

    public AudioClip playerFrustrationUp;
    public AudioClip playerFrustrationDown;

    public AudioClip playerHealthUp;
    public AudioClip playerTakeDamage;

    public AudioClip playerDied;


    public bool bCalledInit;

    public bool bIAmDead;

	// Use this for initialization
	protected override void Start ()
	{
	    base.Start();

        theInput = GameObject.Find("InputManager").GetComponent<InputManager>();

        GameObject anchor = GameObject.Find("FrustrationLightningQuad");
	    frustrationLightningQuad = anchor.GetComponent<MeshFilter>();
 
        Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("PlayerCollide"), LayerMask.NameToLayer("PlayerProjectile"), true);
        Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("PlayerProjectile"), LayerMask.NameToLayer("PlayerProjectile"), true);

        Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("MonsterCollide"), LayerMask.NameToLayer("MonsterProjectile"), true);
        Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("MonsterProjectile"), LayerMask.NameToLayer("MonsterProjectile"), true);
        Physics2D.IgnoreLayerCollision(LayerMask.NameToLayer("MonsterCollide"), LayerMask.NameToLayer("MonsterCollide"), true);

	    bCalledInit = true;
	}
	
    void OnGUI()
    {
    }

    void KillMe(bool bDiedFromEthics)
    {
        if (bIAmDead)
            return;

        bIAmDead = true;

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

        GameManager gm = GameObject.Find("GameManager").GetComponent<GameManager>();
        gm.currentGameState = GameState.waiting_for_game_over;
        gm.fGameOverDelayTimer = 4.0f;
        myAudio.PlayOneShot(playerDied);

        gm.bGameOverFromPlayerEthics = bDiedFromEthics;
        gm.bGameOverFromPlayerDeath = !bDiedFromEthics;
    }

    public void ChangeEthics(float f)
    {
        if (f > 0)
        {
            bEthicsChangeWasPositive = true;
            myAudio.PlayOneShot(playerEthicsUp);
        }
        else
        {
            bEthicsChangeWasPositive = false;
            myAudio.PlayOneShot(playerEthicsDown);
        }

        fRecentEthicsChangeTimer = 1.0f;

        fRemainingEthics = Mathf.Clamp(fRemainingEthics + f, 0.0f, 100.0f);

        if (fRemainingEthics == 0.0f)
            KillMe(true);
    }

    public string GetEthicsStringFromScore( ref float _fRecentEthicsChange, ref bool _bChangeWasPositive, ref bool bShowWarning )
    {
        _fRecentEthicsChange = fRecentEthicsChangeTimer;
        _bChangeWasPositive = bEthicsChangeWasPositive;
        bShowWarning = false;

        string strRet = "";
        if (fRemainingEthics >= 100.0f)
            strRet = "Unimpeachable";
        else if (fRemainingEthics >= 80.0f)
            strRet = "Noble";
        else if (fRemainingEthics >= 60.0f)
            strRet = "Questionable";
        else if (fRemainingEthics >= 40.0f)
            strRet = "Suspect";
        else if (fRemainingEthics >= 20.0f)
        {
            strRet = "Corrupt";
            bShowWarning = true;
        }
        else
        {
            strRet = "Indefensible";
            bShowWarning = true;
        }
        return strRet;
    }

    public override void FixedUpdate()
    {
        bool bIgnoreDropPlatforms = false;
        bool bHoldingDown = theInput.InputHeldThisTurn(InputTypes.down);


        //SHITTY CODE
        #region Shit Code
        if ( bHoldingDown )
            SetState_Crouch();
        else
            SetState_Idle();
        #endregion

        if (bHoldingDown && iJumpCounter == 0)
        {
            m_WhatIsGround = LayerMask.GetMask("Ground");
            bIgnoreDropPlatforms = true;
        }
        else
            m_WhatIsGround = LayerMask.GetMask("Ground", "DropFloorGround");

        if (UpdateGrounded())
            bAmFloorDropping = false;


    }

    public bool PlayerIsFloorDropping()
    {
        return bAmFloorDropping;
    }

    void UpdateFedoraCharge()
    {
        if (fFrustration >= 60.0f)
        {
            //if we're not throwing the fedora, charge it up
            if (!bFedoraIsFlying && fFedoraChargePercentage < 100.0f)
            {
                fFedoraChargePercentage += Time.smoothDeltaTime*25.0f;

                if (fFedoraChargePercentage >= 100.0f)
                {
                    //Show glowing fedora on head
                    fedoraReadyGameObject.SetActive(true);
                }
            }
        }
        else
        {
            bFedoraIsFlying = false;
            fFedoraChargePercentage = 0.0f;
        }
    }

    protected override bool UpdateGrounded()
    {
        bool bRet = base.UpdateGrounded();

        return bRet;
    }

    public float ChangeFrustration(float fDelta)
    {
        if (fDelta > 0.0f)
            myAudio.PlayOneShot(playerFrustrationUp);
        else
            myAudio.PlayOneShot(playerFrustrationDown);

        fFrustration = Mathf.Clamp(fFrustration + fDelta, 0.0f, 100.0f);

        return fFrustration;
        
    }

    void DrawFrustrationLightningBetweenSelfAnd(GameObject target)
    {
        MeshRenderer mr = frustrationLightningQuad.GetComponent<MeshRenderer>();
        mr.enabled = true;

        Vector3 vLightningDelta = target.transform.position - transform.position;
        float fDist = vLightningDelta.magnitude;

        Vector3 lightningPos = transform.position;
        vLightningDelta.Normalize();
        lightningPos += vLightningDelta * fDist * 0.5f;
        frustrationLightningQuad.transform.position = lightningPos;
        frustrationLightningQuad.transform.right = vLightningDelta;

        Vector3 pissss =
            frustrationLightningQuad.transform.localScale;

        pissss.x = fDist;
        if (Random.value < 0.2f)
            pissss.y *= -1.0f;

        frustrationLightningQuad.transform.localScale = pissss;

        Material lightningMaterial = frustrationLightningQuad.GetComponent<MeshRenderer>().material;
        lightningMaterial.mainTextureScale = new Vector2(fDist / 4, 1);
        Vector2 vPants = lightningMaterial.mainTextureOffset;
        vPants.x += Time.smoothDeltaTime * Random.value * -12.05f;
        lightningMaterial.mainTextureOffset = vPants;

    }

    void HideFrustrationLightning()
    {
        MeshRenderer mr = frustrationLightningQuad.GetComponent<MeshRenderer>();
        mr.enabled = false;
    }

    protected override void Update()
    {
        if (!bCalledInit)
            Start();

        base.Update();

        if( transform.position.y < -200.0f)
            TakeDamage(4000.0f);

        if (fRecentEthicsChangeTimer > 0.0f)
            fRecentEthicsChangeTimer -= Time.smoothDeltaTime;

        if (fDamageImmunityTimer > 0.0f)
        {
            fDamageImmunityTimer -= Time.smoothDeltaTime;
            int iLolHax = (int) (fDamageImmunityTimer*100.0f);
            if (iLolHax%4 > 1)
                m_SpriteRenderer.enabled = false;
            else
                m_SpriteRenderer.enabled = true;

        }
        else
        {
            m_SpriteRenderer.enabled = true;
        }

        bool bHoldingDown = theInput.InputHeldThisTurn(InputTypes.down);
        Vector3 vPos = new Vector3();
        //regular jump
        if (iJumpCounter == 0 && theInput.InputJustPressedThisFrame(InputTypes.a))
        {
            myAudio.PlayOneShot(playerJump);

            iJumpCounter++;
            if (theInput.InputHeldThisTurn(InputTypes.up))
                myBody.AddForce(new Vector2(0, 1.5f * JumpForce));
            else if (bHoldingDown)
            {
                myBody.AddForce(new Vector2(0, -0.5f * JumpForce));
                vPos = transform.position;
                vPos.y -= 0.5f;
                transform.position = vPos;
                bAmFloorDropping = true;
            }
            else
                myBody.AddForce(new Vector2(0, JumpForce));
        }

        if (iJumpCounter == 0 || !bHoldingDown)
            bAmFloorDropping = false;

        UpdateFedoraCharge();

        //check dashuu
        if (theInput.IsThisInputDoubleTapped(InputTypes.right))
            dashDirection = InputTypes.right;
        else if (theInput.IsThisInputDoubleTapped(InputTypes.left))
            dashDirection = InputTypes.left;

        if (!theInput.InputHeldThisTurn(dashDirection))
            dashDirection = InputTypes.NO_INPUT;

        float fDelta = 0.0f;

	    bool bOldFacing = bFacingRight;

	    if (theInput.InputHeldThisTurn(InputTypes.right))
	    {
            fDelta = (dashDirection == InputTypes.right ? DashSpeed : WalkSpeed) * Time.smoothDeltaTime;
	        bFacingRight = true;
	    }
        else if (theInput.InputHeldThisTurn(InputTypes.left))
        {
            fDelta = (dashDirection == InputTypes.left ? DashSpeed : WalkSpeed) * Time.smoothDeltaTime * -1.0f;
            bFacingRight = false;
        }

	    if (bOldFacing != bFacingRight)
	    {
	        ToggleFacing();
	    }
        
        vPos = transform.position;
        vPos.x += fDelta;
        transform.position = vPos;

	    if (theInput.InputJustPressedThisFrame(InputTypes.x))
	    {
            FireProjectile();
	    }

        if (fFrustration >= 80.0f)
        {
            if (fTimeUntilNextLightning > 0.0f)
                fTimeUntilNextLightning -= Time.smoothDeltaTime;

            if (fTimeUntilNextLightning <= 0.0f && lightningTarget == null )
            {
                lightningTarget = FindLightningTarget();
                if (lightningTarget == null)
                {
                    fTimeUntilNextLightning = 1.0f;
                    HideFrustrationLightning();
                }
                else
                {
                    myAudio.PlayOneShot(playerLightning);
                    fActiveLightningTimer = 0.5f;
                }
            }

            //shock if we have any lighting to show
            if (lightningTarget != null)
            {
                DrawFrustrationLightningBetweenSelfAnd(lightningTarget.gameObject);
                lightningTarget.TakeDamage(15.0f);

                fActiveLightningTimer -= Time.smoothDeltaTime;
                if (fActiveLightningTimer <= 0.0f)
                {
                    lightningTarget = null;
                    HideFrustrationLightning();
                    fTimeUntilNextLightning = 0.75f + (1.0f*Random.value);
                }
            }

        }
	}

    void OnCollisionEnter2D(Collision2D coll)
    {
        Debug.Log("Collision! Layers touched: " + coll.collider.IsTouchingLayers().ToString());
    }

    public BaseEnemy FindLightningTarget()
    {
        Collider2D[] colliders = Physics2D.OverlapCircleAll(groundCollisionCircle.position, 15.0f, LayerMask.GetMask("MonsterCollide"));
        if (colliders.Length == 0)
            return null;

        int iRandomRoll = Random.Range(0, colliders.Length);
        GameObject go = colliders[iRandomRoll].gameObject;

        if (go != null)
            return go.GetComponent<BaseEnemy>();

        return null;
    }

    public override void TakeDamage( float fDamageAmount)
    {
        if (fDamageImmunityTimer > 0)
            return;

        myAudio.PlayOneShot(playerTakeDamage);

        base.TakeDamage(fDamageAmount);

        if (fHealth > 0.0f)
        {
            int iRoll = Random.Range(1, 5);
            string strAngry = "";
            switch (iRoll)
            {
                case 1:
                    strAngry = "Nuuu!";
                    break;
                case 2:
                    strAngry = "FFFF!";
                    break;
                case 3:
                    strAngry = "OW!";
                    break;
                case 4:
                    strAngry = "GRAH!";
                    break;
            }

            SaySomething(strAngry, 1.0f);
        }
        else
        {
            KillMe(false);
        }
        fDamageImmunityTimer = 1.0f;
    }


    public void ExpressFrustrationAtRejection()
    {
        int iRoll = Random.Range(1, 5);
        string strAngry = "";
        switch (iRoll)
        {
            case 1:
                strAngry = "M'lady... :(";
                break;
            case 2:
                strAngry = "Why won't they love me?";
                break;
            case 3:
                strAngry = "But I'm so NICE!?";
                break;
            case 4:
                strAngry = "Nice guys finish last.";
                break;
        }

        SaySomething(strAngry, 4.0f);
    }

    protected override void SetState_Idle()
    {
        base.SetState_Idle();
        fedoraReadyGameObject.transform.localPosition = new Vector3(0f,0.75f,0f);

    }

    protected override void SetState_Crouch()
    {
        base.SetState_Crouch();
        fedoraReadyGameObject.transform.localPosition = new Vector3(0f, 0.15f, 0f);
    }

    public override void FireProjectile()
    {
        GameObject newShot = GameObject.Instantiate(projectile_BasicShot);

        Vector3 vShotOrigin = new Vector3();
        Vector2 vShotDir = new Vector2();

        GetShotOriginAndDirection(ref vShotOrigin, ref vShotDir);
        newShot.transform.position = vShotOrigin;
        Projectile proj = newShot.GetComponent<Projectile>();
        proj.Launch(vShotDir);

        myAudio.PlayOneShot(playerLand);

        //multishot for frustration
        if (fFrustration >= 20.0f)
        {
            newShot = GameObject.Instantiate(projectile_BasicShot);
            newShot.transform.position = vShotOrigin;
            proj = newShot.GetComponent<Projectile>();
            proj.ProjectileLaunchWiggle = 0.2f;
            proj.Speed = (proj.Speed*0.8f + proj.Speed*0.6f*Random.value);
            proj.Launch(vShotDir);
        }

        if (fFrustration >= 40.0f)
        {
            newShot = GameObject.Instantiate(projectile_BasicShot);
            newShot.transform.position = vShotOrigin;
            proj = newShot.GetComponent<Projectile>();
            proj.ProjectileLaunchWiggle = 0.2f;
            proj.Launch(vShotDir * -1.0f);
        }
        
        if (fFrustration >= 60.0f && !bFedoraIsFlying && fFedoraChargePercentage >= 100.0f)
        {
            if (actualFrostdora == null)
                actualFrostdora = GameObject.Instantiate(Resources.Load<GameObject>("Prefabs/Frostdora"));

            actualFrostdora.transform.position = fedoraReadyGameObject.transform.position;
            fedoraReadyGameObject.SetActive(false);
            actualFrostdora.SetActive(true);

            Frostdora frostdora_component = actualFrostdora.GetComponent<Frostdora>();
            frostdora_component.LaunchFrostdora(vShotDir);

            bFedoraIsFlying = true;
        }
    }

    public void RecoverFedora()
    {
        Debug.Log("Recovered?");
        bFedoraIsFlying = false;
        fFedoraChargePercentage = 0.0f;

    }

    public void GiveHealth(float fDelta)
    {
        GameObject healBurst = Instantiate(prefab_particleHealed);
        healBurst.transform.position = transform.position;
        Destroy(healBurst,3.0f);

        myAudio.PlayOneShot(playerHealthUp);


        fHealth = Mathf.Clamp(fHealth + fDelta, 0.0f, 1000.0f);

        if (fDelta > 0.0f)
        {
            int iRoll = Random.Range(1, 4);
            string strAngry = "";
            switch (iRoll)
            {
                case 1:
                    strAngry = "So Alpha!";
                    break;
                case 2:
                    strAngry = "Yeah!!";
                    break;
                case 3:
                    strAngry = "I can't be stopped!";
                    break;
            }

            SaySomething(strAngry, 4.0f); 
        }

    }

    public void BarkFoundJournalisms()
    {
        int iRoll = Random.Range(1, 4);
        string strAngry = "";
        switch (iRoll)
        {
            case 1:
                strAngry = "Evidence!";
                break;
            case 2:
                strAngry = "It's a conspiracy!";
                break;
            case 3:
                strAngry = "The Agenda revealed!";
                break;
        }

        SaySomething(strAngry, 4.0f); 
    }
}
