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

public enum E_TM_WeaponType
{
    projectile = 0,
    beam,
    hitscan,
}

public class TM_Weapon : MonoBehaviour
{
    public E_TM_WeaponType weaponType = E_TM_WeaponType.projectile;

    [Tooltip("Pew pew!")]
    public GameObject Prefab_Projectile;
    [Tooltip("Used for beam type weapons")]
    public bool bAttachProjectileToWeapon;

    [Tooltip("Offset from origin from which to launch projectiles. Typically the end of the weapon barrel")]
    public Vector2 vFireOriginOffset;

    private Vector3 vFacing;

    [Tooltip("Applied to projectiles to fake 3D in our 2D world")]
    public int iFakeAltitude;

    [Tooltip("Multiplier for base projectile speed")]
    public float ProjectileSpeedMultiplier = 1.0f;

    [Tooltip("Minimum time between trigger pulls and burst starts")]
    public float CooldownTime;
    private float fCooldownRemaining;

    [Space(12)]
    [Header("Burst Fire")]
    [Tooltip("Number of fire events generated from one pull of the trigger.")]
    public int ShotsPerBurst;
    [Tooltip("Delay between each fire event generated")]
    public float DelayBetweenShots;
    private int iShotsLeftInBurst;
    protected float fShotDelay;

    [Tooltip("Use for spread fire to launch multiple projectiles per fire event")]
    public List<float> AnglesToFireMultipleProjectilesFrom;

    [Tooltip("Inaccuracy measured in degrees of variance. Use for spray weapons.")]
    public float ShotInaccuracy;

    [Space(12)]
    [Header("Beam Data")]
    public float BeamLength_Units = 10.0f;
    public float BeamWidth_Units = 1.0f;
    private TM_Projectile attachedBeam;

    [HideInInspector]
    public Vector3 vForceBurstToThisVector = Vector3.zero;

    [HideInInspector]
    public bool bIsFiring;

    public bool bSilent;

    //Vector used to generate a scalar value that increases the shot speed based on the movement of the owner
    private Vector2 vProjectileVelocityAdjustmentFromOwnerMovement;

    // Use this for initialization
    protected virtual void Start()
    {

    }

    // Update is called once per frame
    protected virtual void Update()
    {
        switch (weaponType)
        {
            case E_TM_WeaponType.beam:
                if (attachedBeam == null)
                    bIsFiring = false;
                else
                    HandleBeamProjectile(attachedBeam);
                break;
            case E_TM_WeaponType.projectile:
                if (bIsFiring)
                    TickDownShots();
                break;

        }

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

    public virtual void StartBurst()
    {
        if (fCooldownRemaining > 0.0f)
            return;

        fCooldownRemaining = CooldownTime;

        Fire();
        iShotsLeftInBurst--;
        if (iShotsLeftInBurst <= 0)
        {
            ResetBurst();
            bIsFiring = false;
        }
        else
        {
            bIsFiring = true;
        }
    }

    protected void ResetBurst()
    {
        iShotsLeftInBurst = ShotsPerBurst;
        fShotDelay = 0.0f;
    }

    private void TickDownShots()
    {
        fShotDelay -= Time.deltaTime;
        if (fShotDelay <= 0.0f)
        {
            fShotDelay = DelayBetweenShots;
            Fire();
            iShotsLeftInBurst--;
            if (iShotsLeftInBurst <= 0)
            {
                ResetBurst();
                bIsFiring = false;
            }
        }
    }

    protected virtual void Fire()
    {
        float fModifiedInaccuracy = Random.Range(-ShotInaccuracy, ShotInaccuracy);

        FireOneShot(fModifiedInaccuracy);
        if (AnglesToFireMultipleProjectilesFrom != null && AnglesToFireMultipleProjectilesFrom.Count > 0)
        {
            foreach (float f in AnglesToFireMultipleProjectilesFrom)
                FireOneShot(f + fModifiedInaccuracy);
        }
        fShotDelay = DelayBetweenShots;

    }

    protected virtual TM_Projectile FireOneShot(float deviateAngle)
    {
        GameObject go = Instantiate(Prefab_Projectile);
        TM_Projectile p = go.GetComponent<TM_Projectile>();

        if (weaponType == E_TM_WeaponType.beam)
        {
            TM_AudioManager.PlayClip(p.clip_launchClip);
            HandleBeamProjectile(p);
            return p;
        }

        Vector3 vProjectilePosition = transform.position;
        //if there's an offset, use that instead
        if (vFireOriginOffset != Vector2.zero)
        {
            Vector2 vAdjustedOffset = TM_Utilities.Rotate2DVector(vFireOriginOffset, transform.rotation.eulerAngles.z);
            vProjectilePosition.x += vAdjustedOffset.x;
            vProjectilePosition.y += vAdjustedOffset.y;
        }

        p.transform.position = vProjectilePosition;
        p.fSpeed = Random.Range(p.MinMax_ProjectileSpeed.x, p.MinMax_ProjectileSpeed.y) * ProjectileSpeedMultiplier;
        p.iFakeAltitude = iFakeAltitude;



        Vector3 towardsTarget = transform.up.normalized;

        //Override tracking        
        if (vForceBurstToThisVector != Vector3.zero)
            towardsTarget = vForceBurstToThisVector.normalized;

        if (deviateAngle != 0)
        {
            Vector2 vRotMe = towardsTarget;
            vRotMe = TM_Utilities.Rotate2DVector(vRotMe, deviateAngle);
            towardsTarget.x = vRotMe.x;
            towardsTarget.y = vRotMe.y;
        }

        p.vDirection = towardsTarget;

        if (bAttachProjectileToWeapon)
        {   // Parent the projectile to this
            go.transform.parent = transform;
        }

        //if we have an adjustment vector, use it to change the speed of the projectile
        Vector2 vNormalizedAdjustment = vProjectileVelocityAdjustmentFromOwnerMovement.normalized;
        float fAdjustedSpeed = vProjectileVelocityAdjustmentFromOwnerMovement.magnitude;

        //how much of the adjustment do we want to use
        float fMultiplier = Vector2.Dot(vNormalizedAdjustment, p.vDirection)*fAdjustedSpeed;
        //Debug.Log("fMultiplier is " + fMultiplier + " when dotting " + vNormalizedAdjustment + " with " + p.vDirection + " times " + fAdjustedSpeed);
        p.fSpeed += fMultiplier;



        p.Launch( p.transform.position, bSilent );

        return p;
    }

    //Beam projectiles are simply attached to the weapon and don't have speed of thier own
    void HandleBeamProjectile(TM_Projectile p)
    {
        bIsFiring = true;

        //attach it to us
        attachedBeam = p;
        p.bLetSomeoneElseMoveMe = true;
       
        //p.transform.parent = transform;
        MeshRenderer mr = p.GetComponent<MeshRenderer>();
        mr.enabled = true;
        mr.sortingLayerName = "Lazar";

        Vector3 vBeamBase = transform.position;

        if (vFireOriginOffset != Vector2.zero)
        {
            Vector2 vAdjustedOffset = TM_Utilities.Rotate2DVector(vFireOriginOffset, transform.rotation.eulerAngles.z);
            vBeamBase.x += vAdjustedOffset.x;
            vBeamBase.y += vAdjustedOffset.y;
        }

        Vector3 vTargetPosition = vBeamBase + (transform.up * BeamLength_Units);
        //Get the vector between us and them.
        Vector3 vBeamDelta = vTargetPosition - vBeamBase;
        vBeamDelta.Normalize();

        //place the quad at the mid point between us and them, and rotate it to face correctly along the vector
        Vector3 vBeamPosition = vBeamBase;

        vBeamPosition += vBeamDelta * BeamLength_Units * 0.5f;

        p.transform.position = vBeamPosition;
        p.transform.right = vBeamDelta;

        Debug.Log("vBeamDelta issss " + vBeamDelta);

        //scale the quad to match the distance between us and them, the variance here is for laser pulsing effect
        Vector3 pissss = p.transform.localScale;
        pissss.x = BeamLength_Units;
        pissss.y = BeamWidth_Units + (0.1f + Random.value * 0.2f);
        p.transform.localScale = pissss;

        //Scale the texture on the quad and rotate through it
        Material beamMaterial = p.GetComponent<MeshRenderer>().material;

        //hack for LD35: all beam textures are 256 / 32, so 8 to 1
        float fBeamRatio = BeamLength_Units/ (8 * BeamWidth_Units);
        beamMaterial.mainTextureScale = new Vector2(fBeamRatio, 1);
        Vector2 vPants = beamMaterial.mainTextureOffset;
        vPants.x += Time.smoothDeltaTime * Random.value * -12.05f;
        beamMaterial.mainTextureOffset = vPants;

    }

    public void SetVelocityAdjustmentVector(Vector2 vAdjustment)
    {
        vProjectileVelocityAdjustmentFromOwnerMovement = vAdjustment;
    }
}

/* 

Good code for tracking with 2D turrets

 *     public override void UpdateMotion()
    {
        Vector3 towardsPlayer = playerScript.transform.position - transform.position;
        towardsPlayer.Normalize();
        transform.right = Vector3.Cross(towardsPlayer, new Vector3(0, 0, 1));
    }

    public override void StayVertical()
    {
       
    }

    public override void UpdateAttacks()
    {
        Vector3 towardsPlayer = playerScript.transform.position - transform.position;

        towardsPlayer.x += -0.2f + Random.value*0.4f;
        towardsPlayer.Normalize();

        for (int t = 0; t < Attacks.Count(); t++)
        {
            Attacks[t].Update();

            if (transform.position.x < 12.0f)
            {
                float fShotSpeed = 15.0f + (5.5f * mcs.GetEnemySpeedMultiplier());
                Attacks[t].TryFire(transform.position, towardsPlayer, fShotSpeed);
            }
        }
    }
*/
