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

[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(AudioSource))]
public class WeaponHitscan : MonoBehaviour
{
    [Header("Stats")]
    public float damage = 3f;
    public float fireRate = 1f;
    public int pelletCount = 1;
    public int ammoConsumption = 1;
    public float spread = 0f;
    public float impactForce = 1f;

    [Header("Reloading")]
    public int clipSize;
    private int currentAmmo;

    public float reloadDelay;
    public float reloadTime;
    public int reloadAmount;

    public bool magReload = false;
    [HideInInspector] public bool isReloading = false;

    [HideInInspector] public Animator anim;
    [HideInInspector] public AudioSource sound;

    [Header("FX")]
    public ParticleSystem muzzleFlash;
    public GameObject bulletHole;

    public AudioClip shootSound;
    public AudioClip reloadSound;
    public Vector2 recoil;

    [Header("Casing")]
    public Transform casingSpawnPosition;
    public GameObject casing;
    public float casingDelay;
    public float casingFlyForce;


    protected float nextTimeToFire = 1f;
    protected GameObject cam; protected PlayerStats ps;
    private CameraRecoil recoilFunc;

    void Start()
    {
        ps = GameObject.Find("Player").GetComponent<PlayerStats>();
        cam = GameObject.Find("Main Camera");
        recoilFunc = cam.transform.parent.GetComponent<CameraRecoil>();

        anim = GetComponent<Animator>();
        sound = GetComponent<AudioSource>();

        currentAmmo = clipSize;
    }

    void Update()
    {
        if(ps.textClip) ps.textClip.text = currentAmmo.ToString();

        if (!GetComponentInParent<WeaponSwitch>().isHolstering)
        {
            if (isReloading) return;

            if (currentAmmo <= 0 && ps.globalAmmo > 0 || Input.GetKey(KeyCode.R) && currentAmmo < clipSize)
            {
                StartCoroutine(Reload());
                return;
            }

            if (Input.GetMouseButton(0) && Time.time >= nextTimeToFire)
            {
                if (currentAmmo > 0)
                {
                    nextTimeToFire = Time.time + 1f / fireRate;
                    StartCoroutine(ShootChecker());
                }
            }
        }
    }

    void Shoot()
    {
        for (int i = 0; i < pelletCount; i++)
        {
            Quaternion hSpreadAngle = Quaternion.AngleAxis(Random.Range(-spread, spread), new Vector3(0, 1, 1));
            Quaternion vSpreadAngle = Quaternion.AngleAxis(Random.Range(-spread, spread), new Vector3(1, 0, 2));

            Vector3 newVector = hSpreadAngle * vSpreadAngle * cam.transform.forward;
            RaycastHit hit;

            if (Physics.Raycast(cam.transform.position, newVector, out hit))
            {
                GameObject target = null;//hit.transform.GetComponent<Enemy>();
                if (target != null)
                {
                    //target.TakeDamage(Random.Range(damage * 1, damage * 3));
                    //GameObject blood = Instantiate(bloodEffect, hit.point, Quaternion.LookRotation(hit.normal));
                    //Destroy(blood, 3f);
                }
                else
                {
                    ParticlesContainer parList = GameObject.Find("GameManager").GetComponent<ParticlesContainer>();

                    if (hit.collider.GetComponent<Terrain>()) return;
                    if (hit.collider.GetComponent<MeshRenderer>() != null && hit.collider.GetComponent<MeshRenderer>().material.name.Contains("glass")
                        || hit.collider.GetComponentInChildren<MeshRenderer>().material.name.Contains("glass"))
                    {
                        GameObject newGlasshole = Instantiate(parList.glassHole, hit.point, Quaternion.LookRotation(hit.normal) * parList.glassHole.transform.rotation);
                        newGlasshole.transform.SetParent(hit.collider.transform); Destroy(newGlasshole, 60f);

                        var savedVolume = newGlasshole.GetComponent<AudioSource>().volume;
                        newGlasshole.GetComponent<AudioSource>().volume = savedVolume / pelletCount;
                        newGlasshole.transform.parent = hit.transform;
                    }
                    else
                    {
                        if (!hit.collider.gameObject.name.Contains("pickup"))
                        {
                            GameObject impact = Instantiate(bulletHole, hit.point, Quaternion.LookRotation(hit.normal));
                            impact.transform.parent = hit.collider.transform; Destroy(impact, 60f);
                        }

                        if (hit.collider.GetComponent<MeshRenderer>() != null)
                        {
                            if (hit.collider.GetComponent<MeshRenderer>().material.name.Contains("concrete") || hit.transform.GetComponentInChildren<MeshRenderer>().material.name.Contains("concrete"))
                            {
                                GameObject crumble = Instantiate(parList.concreteCrumble, hit.point, Quaternion.LookRotation(hit.normal) * Quaternion.Euler(-30, 0, 0));

                                var savedVolume = crumble.GetComponent<AudioSource>().volume;
                                crumble.GetComponent<AudioSource>().volume = savedVolume / pelletCount;
                            }
                            if (hit.collider.GetComponent<MeshRenderer>().material.name.Contains("wood") || hit.transform.GetComponentInChildren<MeshRenderer>().material.name.Contains("wood"))
                            {
                                GameObject crumble = Instantiate(parList.woodCrumble, hit.point, Quaternion.LookRotation(hit.normal) * Quaternion.Euler(-30, 0, 0));

                                var savedVolume = crumble.GetComponent<AudioSource>().volume;
                                crumble.GetComponent<AudioSource>().volume = savedVolume / pelletCount;
                            }
                            if (hit.collider.GetComponent<MeshRenderer>().material.name.Contains("metal") || hit.transform.GetComponentInChildren<MeshRenderer>().material.name.Contains("metal"))
                            {
                                GameObject crumble = Instantiate(parList.metalCrumble, hit.point, Quaternion.LookRotation(hit.normal) * Quaternion.Euler(-30, 0, 0));

                                var savedVolume = crumble.GetComponent<AudioSource>().volume;
                                crumble.GetComponent<AudioSource>().volume = savedVolume / pelletCount;
                            }
                        }

                        Rigidbody rb = hit.transform.GetComponent<Rigidbody>();
                        if (rb != null) rb.AddForce(newVector * impactForce);
                    }

                    LightDestroy ld = hit.transform.GetComponent<LightDestroy>();
                    if (ld != null) ld.ChangeMat();

                    Destructible dest = hit.collider.transform.GetComponent<Destructible>();
                    if (dest != null) dest.TakeDamage(damage);
                    }
                }
            }

        currentAmmo -= ammoConsumption;
    }

    IEnumerator ShootChecker()
    {
        anim.Play("fire");
        Shoot();

        int newRecoil = Random.Range(((int)recoil.x), (int)recoil.y);
        recoilFunc.Recoil(newRecoil);
        
        if (sound != null) { sound.clip = shootSound; sound.Play(); }
        if(muzzleFlash != null) muzzleFlash.Play();

        if(casing != null)
        {
            yield return new WaitForSeconds(casingDelay);

            GameObject shell = Instantiate(casing, casingSpawnPosition.position, casingSpawnPosition.rotation);
            shell.GetComponent<Rigidbody>().AddForce((casingSpawnPosition.transform.up * casingFlyForce + -transform.forward) * 2f, ForceMode.Impulse);
            Destroy(shell, 20f);
        }
    }

    IEnumerator Reload()
    {
        isReloading = true;
        //yield return new WaitForSeconds(reloadDelay /2);
        anim.Play("reload");
        yield return new WaitForSeconds(reloadDelay);

        if (magReload)
        {
            if (sound != null)
                   { sound.Stop(); sound.clip = reloadSound; sound.Play(); } 

            yield return new WaitForSeconds(reloadTime);

            int reloadAmount2 = clipSize - currentAmmo;
            reloadAmount2 = (ps.globalAmmo - reloadAmount2) >= 0 ? reloadAmount2 : ps.globalAmmo;
            currentAmmo += reloadAmount2;
            ps.globalAmmo -= reloadAmount2;

            isReloading = false;
        }
        else
        {
            StartCoroutine(ReloadUnmag());
        }
    }

    IEnumerator ReloadUnmag()
    {
        if (currentAmmo < clipSize)
        {
            anim.Play("");
            anim.Play("reload_put");
            if (sound != null)
                { sound.Stop(); sound.clip = reloadSound; sound.Play(); }

            yield return new WaitForSeconds(reloadTime / 2);

            currentAmmo += reloadAmount;
            ps.globalAmmo -= reloadAmount;

            StartCoroutine(ReloadUnmag());
        }

        if (currentAmmo == clipSize || ps.globalAmmo == 0)
        {
            anim.Play("reload_finish");
            yield return new WaitForSeconds(reloadTime / 2);
            isReloading = false;
                
            yield break;
        }
    }
}