using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using Random = UnityEngine.Random;

[RequireComponent(typeof(TM_CombatComponent))]
public class EnemyAI : MonoBehaviour
{
    private GameManager theGame;
    private TM_CombatComponent myCC;
    private AIMove_Base myAIMovement;

    public EShipForm primaryAttackForm;

    public float MaxHealth;
    private float fCurrentHealth;


    public PlayerController attackTarget;

    public Vector2 MinMax_NumShrapnels;
    public GameObject prefab_debrisOnDeath;

    public int iScoreValue;

    public AudioClip clip_OnDeath;
    public float ChanceOfLoot;

    [Space(18)] 
    [Header("Shooting")] 
    public Vector2 MinMax_DelayBeforeShoot;
    private float fTimeTillNextShot;

    private bool bDead = false;

    private List<Func<GameObject, bool>> listOfAltFireFunctions;

    void Awake()
    {
        theGame = GameObject.Find("GameManager").GetComponent<GameManager>();
        myCC = GetComponent<TM_CombatComponent>();
        myAIMovement = GetComponent<AIMove_Base>();
        fCurrentHealth = MaxHealth;
        fTimeTillNextShot = Random.Range(MinMax_DelayBeforeShoot.x, MinMax_DelayBeforeShoot.y);
        listOfAltFireFunctions = new List<Func<GameObject, bool>>();
    }

	void Start () 
    {
	    myCC.AddOnHitFunction(OnHitByProjectile);
	}

    public void AddAltFireFunction( Func<GameObject,bool> func  )
    {
        listOfAltFireFunctions.Add(func);
    }
	
	// Update is called once per frame
	void Update () 
    {
        //attack the player always for now
	    attackTarget = attackTarget == null ? GameObject.Find("Player").GetComponent<PlayerController>() : attackTarget;

	    //do something motion related based on our AttackTarget
        if( myAIMovement != null )
    	    myAIMovement.UpdateMovement(attackTarget);

	    //maybe shoot at it
        UpdateWeapons(attackTarget);

    }

    protected virtual void UpdateWeapons(PlayerController attackTarget)
    {
        TM_Weapon weapon = GetComponent<TM_Weapon>();
        if (weapon == null)
            return;

        if( fTimeTillNextShot > 0.0f)
            fTimeTillNextShot -= Time.deltaTime;

        Vector2 vToTarget2D = attackTarget.transform.position - transform.position;
        if (vToTarget2D.sqrMagnitude > 50.0f*50.0f)
            return;

        if (fTimeTillNextShot <= 0.0f)
        {
            if (primaryAttackForm == attackTarget.currentForm)
            {
                if (myAIMovement != null && !myAIMovement.AllowTurningToFire())
                {
                    weapon.vForceBurstToThisVector = (attackTarget.transform.position - transform.position).normalized;
                }
                else
                {
                    weapon.transform.up = (attackTarget.transform.position - transform.position).normalized;
                    weapon.vForceBurstToThisVector = Vector3.zero;
                }
    
                weapon.StartBurst();
            }
            else
            {
                //do a special thing if we have a special thing
                for (int t = 0; t < listOfAltFireFunctions.Count; t++)
                    listOfAltFireFunctions[t](gameObject);
            }

            fTimeTillNextShot = Random.Range(MinMax_DelayBeforeShoot.x, MinMax_DelayBeforeShoot.y);
        }
    }

    public bool OnHitByProjectile( TM_Projectile p)
    {
        // Powerbeam with -1 altitude fucks all and loves none
        if (p.iFakeAltitude >= 0)
        {
            if (p.iFakeAltitude == 0f && primaryAttackForm == EShipForm.triangle)
                return false;

            if (p.iFakeAltitude == 1f && primaryAttackForm == EShipForm.square)
                return false;
        }

        Vector3 impactDirection = transform.position - p.transform.position;
        impactDirection.z = 0;
        impactDirection.Normalize();

        if( myAIMovement != null )
            myAIMovement.AddImpulse(impactDirection*p.fDamageForce);

        fCurrentHealth -= p.fDamage;
        if (fCurrentHealth <= 0.0f)
            OnKilled();
        return true;
    }

    public void OnKilled()
    {
        if (bDead)
            return;

        bDead = true;
        if( prefab_debrisOnDeath != null )
        {
            int iNumShrapnels = Random.Range((int)MinMax_NumShrapnels.x, (int)MinMax_NumShrapnels.y + 1);
            for (int t = 0; t < iNumShrapnels; t++)
            {
                GameObject go = Instantiate(prefab_debrisOnDeath);
                go.transform.position = transform.position;
                DebrisComponent dc = go.GetComponent<DebrisComponent>();
                dc.Launch();
            }
        }

        TM_AudioManager.PlayClip(clip_OnDeath);

        theGame.AddScore(iScoreValue);

        if( Random.value <= ChanceOfLoot )
            theGame.SpawnCollectablesFromTreasureHex(transform.position);

        if (MaxHealth >= 1000)
        {
            for(int t=0; t < 10; t++)
                theGame.SpawnCollectablesFromTreasureHex(transform.position);

        }
        else if (MaxHealth >= 200)
        {
            theGame.SpawnCollectablesFromTreasureHex(transform.position);
        }

        Destroy(gameObject);
    }

    //jostle away, and don't shoot for a few seconds
    public void HitByClearingRing(Vector3 vFromVector)
    {
        if( myAIMovement != null )
            myAIMovement.AddImpulse(vFromVector * Random.Range(48.0f,60.0f));
    
        //fTimeTillNextShot += 3.0f;
        TM_Weapon weapon = GetComponent<TM_Weapon>();
        if (weapon != null)
            weapon.bIsFiring = false;
    }
}
