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

public class LDGameActor : MonoBehaviour
{
    public Vector3 vWorldPos;

    [Header("Base Stats")]
    public Vector2 MaxHealthRange;
    protected float fMaxHealth;
    protected float fCurrentHealth;

    public float MaxJuice;
    private float fCurrentJuice;

    public float TimeToDestroyAfterDying;
    protected bool bDeadAndDying;

    public GameObject Prefab_ExplosionOnDeath;
    public Vector2 MinMaxExplosionsOnDeath;
    public float MaxExplosionRadius;
    public EFaction Faction;
    public int ScoreValueOnDeath;
    public AudioClip clip_OnDeath;

    [Header("Shadow and Verticality")]
    public float fDistanceFromGround;
    public GameObject myShadow;
    public float ZSortValue = -1f;

    protected TM_MovementComponent myMovementComponent;
    private TM_SpriteAnimator myAnimComponent;
    private LDCameraManager mainCamera;

    private ECompassDirection facing_NESW;

    protected GameManager theGame;

    private LDGameActor myAnchorActor;

    protected virtual void Awake()
    {
        myMovementComponent = GetComponent<TM_MovementComponent>();
        mainCamera = Camera.main.GetComponent<LDCameraManager>();
        myAnimComponent = GetComponent<TM_SpriteAnimator>();

        facing_NESW = ECompassDirection.east;
    }

	protected virtual void Start ()
	{
        theGame = GameManager.GetGame();
	    fCurrentJuice = MaxJuice;
	    fMaxHealth = Random.Range(MaxHealthRange.x, MaxHealthRange.y);
        fCurrentHealth = fMaxHealth;

	    LDCombatComponent ldc = GetComponent<LDCombatComponent>();
	    if (ldc != null)
	    {
	        ldc.AddOnHitFunction(OnHitByProjectile);
	    }
	}
	
	protected virtual void Update ()
	{
        if (theGame.GetGameState() != EGameState.gameplay)
        {
            return;
        }

	    UpdateShadow();
	    UpdateMovementAndTransformPosition();
	}

    public virtual Vector2 GetCameraFocusPosition()
    {
        return vWorldPos;
    }

    protected void UpdateShadow()
    {
        if (myShadow != null)
        {
            Vector3 vShadowOffset = new Vector3(0f, 0f, -ZSortValue - 0.1f);
            vShadowOffset.y -= fDistanceFromGround;
            myShadow.transform.localPosition = vShadowOffset;

            myShadow.GetComponent<SpriteRenderer>().color = Camera.main.backgroundColor;
        }
            
    }

    protected void UpdateMovementAndTransformPosition()
    {
        if (myMovementComponent != null)
        {
            Vector3 vOldWorldPos = vWorldPos;
            Vector3 vDesiredMove = myMovementComponent.GetDesiredMove();
            vWorldPos += vDesiredMove;

            //check for collision
        }


        //move to draw component
        Vector3 vDrawPos = mainCamera.transform.position;
        vDrawPos += vWorldPos - (Vector3)mainCamera.GetWorldPosition();

        //so stuff floats
        vDrawPos.y += fDistanceFromGround;
        vDrawPos.z = ZSortValue;

        //quantize for pixel perfection
        vDrawPos = mainCamera.QuantizeVectorForPixelPerfection(vDrawPos);

        transform.position = vDrawPos;

        //anims
        /*
        float xDelta = vWorldPos.x - vOldWorldPos.x;
        float yDelta = vWorldPos.y - vOldWorldPos.y;
        UpdateMovementAnims(xDelta, yDelta);
        */

    }

    protected void UpdateMovementAnims(float xDelta, float yDelta)
    {
        ECompassDirection oldDir = facing_NESW;

        if (xDelta != 0f || yDelta != 0f)
        {
            float xAbs = Mathf.Abs(xDelta);
            float yAbs = Mathf.Abs(yDelta);

            //If the change is mostly horizontal, flip if we need to
            if (xAbs > yAbs)
            {
                if (xDelta > 0)
                {
                    facing_NESW = ECompassDirection.east;
                }
                else
                {
                    facing_NESW = ECompassDirection.west;
                }
            }
            else
            {
                if (yDelta > 0)
                {
                    facing_NESW = ECompassDirection.north;
                }
                else
                {
                    facing_NESW = ECompassDirection.south;
                }
            }
        }

        if (oldDir != facing_NESW)
        {
            switch (facing_NESW)
            {
                case ECompassDirection.north:
                    myAnimComponent.StartIfNotRunning("WalkNorth");
                    break;
                case ECompassDirection.south:
                    myAnimComponent.StartIfNotRunning("WalkSouth");
                    break;
                case ECompassDirection.east:
                    myAnimComponent.StartIfNotRunning("WalkEast");
                    break;
                case ECompassDirection.west:
                    myAnimComponent.StartIfNotRunning("WalkWest");
                    break;
            }
        }
    }

    public virtual bool CanBeTargeted()
    {
        return !bDeadAndDying;
    }

    public virtual Vector2 GetTargetingPosition()
    {
        Vector2 vRet = vWorldPos;
        vRet.y += fDistanceFromGround;

        return vRet;
    }

    public virtual void TakeDamage(float fDamage, LDGameActor source)
    {
        if (bDeadAndDying)
        {
            return;
        }

        fCurrentHealth -= fDamage;

        //do something if ded
        if (fCurrentHealth <= 0f)
        {
            OnKilled(source);

            if (Faction == EFaction.player && gameObject != theGame.thePlayer.gameObject)
            {
                theGame.MaybeAlartPlayerAboutBase(vWorldPos);
            }
        }
    }

    public virtual bool OnHitByProjectile(TM_Projectile proj)
    {
        //who did this!?
        TM_CombatComponent tc = proj.owningCombatComponent;
        LDGameActor hittingActor = tc == null ? null : tc.GetComponent<LDGameActor>();
        if (hittingActor == null)
        {
            //uh
        }
        if (proj.fDamage > 0f)
        {
            TakeDamage(proj.fDamage, hittingActor);
        }

        return true;
    }

    public virtual void OnKilled( LDGameActor source)
    {
        if (bDeadAndDying)
        {
            return;
        }

        bDeadAndDying = true;

        if (source != null && source.Faction == EFaction.player)
        {
            theGame.AddScore(ScoreValueOnDeath);
        }

        theGame.theAIManager.RemoveFromLists(gameObject);

        if (clip_OnDeath != null)
        {
            TM_AudioManager.PlayClip(clip_OnDeath);
        }

        if (Prefab_ExplosionOnDeath != null)
        {
            int iNumFooms = Random.Range((int) MinMaxExplosionsOnDeath.x, (int) MinMaxExplosionsOnDeath.y + 1);
            for (int t = 0; t < iNumFooms; t++)
            {
                Vector2 vFoomPos = GetTargetingPosition() + (Random.insideUnitCircle.normalized) * (Random.Range(0f, MaxExplosionRadius));
                
                if (Prefab_ExplosionOnDeath == theGame.Prefab_Multifoom)
                {
                    theGame.PlayMultifoom(vFoomPos);
                    continue;
                }

                GameObject go =  theGame.PlayParticleEffect( vFoomPos, Prefab_ExplosionOnDeath);
                TM_SpriteAnimator anim = go.GetComponent<TM_SpriteAnimator>();
                if (anim != null)
                {
                    anim.PlayAnim();
                    anim.fDelayBeforeStart = 0f + (Random.Range(0.02f, 0.04f) * t);
                }
            }
        }

        if (TimeToDestroyAfterDying >= -0f)
        {
            Destroy(gameObject, TimeToDestroyAfterDying);
        }
        
    }

    public bool IsDead()
    {
        return bDeadAndDying;
    }

    public virtual bool SpendJuice(float fJuice)
    {
        if (fCurrentJuice <= 0f)
        {
            return false;

        }
        fCurrentJuice -= fJuice;
        if (fCurrentJuice < 0f)
        {
            fCurrentJuice = 0f;
        }

        return true;

    }

    public void GiveHealth(float fValue)
    {

        fCurrentHealth += fValue;
        if (fCurrentHealth > fMaxHealth)
        {
            fCurrentHealth = fMaxHealth;
        }
    }

    public int GetHealth()
    {
        return (int) fCurrentHealth;
    }

    public virtual void OnCollectPickup(LDPickupProjectile pickup)
    {
        
    }

    public virtual Vector2 GetPickupCollectionPosition()
    {
        return vWorldPos;
    }

    //Am I shooting at something? Running from something?
    public virtual LDGameActor GetLastTarget()
    {
        return null;
    }

    public virtual void SetAnchorActor(LDGameActor anchor)
    {
        myAnchorActor = anchor;
    }

    public virtual LDGameActor GetAnchorActor()
    {
        return myAnchorActor;
    }
}
