//Fear System by Caleb Bernatchez

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Linq;
using ShadowDetect;

public class FearSystem : MonoBehaviour, IDataPersistence {

    public bool _surroundedLight;
    [Separator("Radius Detection")]
    public float radiusDetection = 15f;

    [Separator("Layer to Fear")]
    public LayerMask fearMask;
    public LayerMask obstacleMask;
    public Transform playerHead;

    [Separator("Audio Source")]
    public AudioSource fearBreathing;

    [Separator("Decrepitude")]
    public List<Transform> decrepitudeList = new List<Transform>();

    [Separator("Fear Amount")]
    public float currentFear = 0;
    public float maxFear = 100f;

    [Separator("Fear Slider")]
    public Slider fearSlider;
	public Slider sanitySlider;

    [Separator("Number Of Enemies")]
    public int currentEnemy;
    public int enemyMax = 15;
    public bool maxreached = false;

    [Separator("Intensity")]
    public int normal = 5;
    public int medium = 10;
    public int high = 15;

    [Separator("Sanity")]
    public float resetTimer;
    public float timerToSuicide;
    public bool timerIsRunning;
    public bool isInsane;

    [Separator("Shadow People Prefab")]
    public GameObject shadowPeoplePrefab;
    public GameObject shadowPeopleInsaneModePrefab;

    [Separator("Shadow People Listing")]
    private List<GameObject> listOfAllNearbyShadow = new List<GameObject>();
    private List<GameObject> listOfAllAwayShadow = new List<GameObject>();

    private CameraFilterPack_3D_Anomaly fearAnomaly;
    private PlayerVitals playerVitals;
    private RaycastHit hit;
    private float spawnMeleeNext = 0.0f;
    private float spawnMeleeRate = 0.8f;
    private LightFlickerEffect lightFlickerEffect;
	public GameObject[] fires;

    private void Awake()
    {
        if (menuScript1.PlayerSelected == 1)
        {
            resetTimer = 20;
        }
        else if (menuScript1.PlayerSelected == 2)
        {
            resetTimer = 30;
        }
        else if (menuScript1.PlayerSelected == 3)
        {
            resetTimer = 15;
        }
    }
    private void Start()
    {
        fearSlider.interactable = false;
        fearSlider.maxValue = maxFear;
        fearSlider.value = currentFear;
		sanitySlider.value = currentFear;
        playerVitals = GetComponent<PlayerVitals>();
        lightFlickerEffect = GetComponentInChildren<LightFlickerEffect>();
        fearAnomaly = Camera.main.GetComponent<CameraFilterPack_3D_Anomaly>();
        timerToSuicide = resetTimer;
        timerIsRunning = false;
        isInsane = false;

        StartCoroutine(FearDetection());

		fires = GameObject.FindGameObjectsWithTag("Fire");

    }
    void Update() {

        foreach (GameObject fire in fires)
		{
			if (timerToSuicide < resetTimer) {
				if (Vector3.Distance(transform.position, fire.transform.position) <= 4 ) {
					timerToSuicide += 0.05f;
				}
			}
				
		}
		fearSlider.value = 100 * (timerToSuicide / resetTimer);
		sanitySlider.value = currentFear;
        fearAnomaly.Intensity = currentFear / 50;
        if (currentEnemy <= 0)
        {
            currentEnemy = 0;
            lightFlickerEffect.enabled = false;
        }
        maxreached = currentEnemy >= enemyMax;
        timerIsRunning = currentFear >= maxFear;
        currentEnemy = listOfAllNearbyShadow.Count + listOfAllAwayShadow.Count;

        if (maxreached)
        {
            if (currentEnemy > enemyMax)
            {
                currentEnemy = enemyMax;
            }
        }

        if (currentFear >= 50 && currentFear < 75)
        {
            enemyMax = normal;
            lightFlickerEffect.enabled = true;
        }

        else if (currentFear >= 75 && currentFear < 90)
        {
            enemyMax = medium;
            lightFlickerEffect.enabled = true;
        }

        else if (currentFear >= 90)
        {
            enemyMax = high;
            lightFlickerEffect.enabled = true;
        }

        if (decrepitudeList.Count >= 1)
        {
            currentFear += (decrepitudeList.Count * Time.deltaTime);
            if (currentFear > maxFear) { currentFear = maxFear; }
            if (currentFear < 0) { currentFear = 0; }
        }

        else
        {
            currentFear -= (2.5f * Time.deltaTime);
            if (currentFear > maxFear) { currentFear = maxFear; }
            if (currentFear < 0) { currentFear = 0; }
        }

        currentFear = Mathf.Clamp(currentFear, 0, 100);
        if (currentFear > maxFear) { currentFear = maxFear; }
        if (currentFear < 0) { currentFear = 0; }

        if (timerIsRunning)
        {
            if (timerToSuicide > 0)
            {
                timerToSuicide -= Time.deltaTime;
            }
            else
            {
                if (!playerVitals.isSuiciding && !playerVitals.isDead)
                {
                    timerIsRunning = false;
                    timerToSuicide = resetTimer;
                    playerVitals.isSuiciding = true;
                    playerVitals.StartCoroutine(playerVitals.CharacterSuicide());
                    StartCoroutine(DestroyWithTag("ShadowPeople"));
                }
            }
        }
        if (timerToSuicide <= 0)
        {
            timerIsRunning = false;
            timerToSuicide = resetTimer;
            playerVitals.isSuiciding = true;
            playerVitals.StartCoroutine(playerVitals.CharacterSuicide());
            StartCoroutine(DestroyWithTag("ShadowPeople"));
        }

        if (currentFear >= maxFear)
        {
            isInsane = true;
        }

        else
        {
            isInsane = false;
        }

        if (!playerVitals.isDead || !playerVitals.isSuiciding)
        {
            if (currentFear > 10 && !fearBreathing.isPlaying)
            {
                fearBreathing.Play();
                fearBreathing.loop = true;
            }

            else if (currentFear < 10 && fearBreathing.isPlaying)
            {
                fearBreathing.Stop();
                fearBreathing.loop = false;
            }
        }

        else
        {
            fearBreathing.Stop();
            fearBreathing.loop = false;
        }

        if (currentFear > 50)
        {
            SpawnEnemy();
            ListShadowPeople(); 
            GetObjectsOutSideOftheSpehere();
        }
        else if (currentFear < 50)
        {
            if (listOfAllNearbyShadow != null)
            {
                foreach (GameObject shadow in listOfAllNearbyShadow)
                {
                    StartCoroutine(DestroyWithTag("ShadowPeople"));
                    currentEnemy--;
                }
            }
        }
    }

    IEnumerator FearDetection()
    {
        while (true)
        {
            decrepitudeList.Clear();
            ListDecrepitude();
            /*foreach (Transform decrepitude in decrepitudeList) { 
                Debug.DrawLine(playerHead.position, decrepitude.position, Color.yellow);
        }*/
            yield return new WaitForSeconds(1f);
        }
    }

    List<Transform> ListDecrepitude()
    {
        decrepitudeList.Clear();
        Collider[] colliders = Physics.OverlapSphere(transform.position, radiusDetection, fearMask);
        foreach (Collider col in colliders)
        {
            if (colliders.Length >= 1)
            {
                if (!Physics.Linecast(playerHead.position, col.transform.position, out hit, obstacleMask))
                {
                    //Debug.DrawLine(playerHead.position, col.transform.position, Color.green);

                    if (!playerVitals.LightOn || playerVitals.flashlightSlider.value <= 0 || !playerVitals.GlowStickON || !_surroundedLight)
                    {
                        //Debug.Log("Fear");
                        decrepitudeList.Add(col.transform);
                    }
                    if ((playerVitals.LightOn && playerVitals.flashlightSlider.value >= 1) || playerVitals.GlowStickON || _surroundedLight)
                    {
                        //Debug.Log("Light Reduces Fear");
                        decrepitudeList.Remove(col.transform);
                    }
                }

                else if (Physics.Linecast(playerHead.position, col.transform.position, out hit, obstacleMask))
                {

                    //Debug.Log("Obstacle Reduces Fear");
                    //Debug.Log(hit.collider.transform.name);
                    decrepitudeList.Remove(col.transform);
                }
            }

            else if (colliders.Length < 1)
            {
                decrepitudeList.Remove(col.transform);
                //Debug.Log("No Decrepitude Around");
            }
            else if (colliders.Length < 1 && (playerVitals.LightOn && playerVitals.flashlightSlider.value >= 1) || playerVitals.GlowStickON || _surroundedLight)
            {
                decrepitudeList.Remove(col.transform);
                //Debug.Log("No Decrepitude Around + Light");
            }
        }
        return decrepitudeList;
    }
    List<GameObject> ListShadowPeople()
    {
        if (!maxreached)
        {
            listOfAllNearbyShadow.Clear();
            GameObject[] allObjects = GameObject.FindGameObjectsWithTag("ShadowPeople");
            for (int i = 0; i < allObjects.Length; i++)
            {
                if (Vector3.Distance(allObjects[i].transform.position, transform.position) <
                                                         radiusDetection)
                {
                    listOfAllNearbyShadow.Add(allObjects[i]);
                }
            }
        }
        return listOfAllNearbyShadow;
    }

    List<GameObject> GetObjectsOutSideOftheSpehere()
    {
        listOfAllAwayShadow.Clear();
        GameObject[] allObjects = GameObject.FindGameObjectsWithTag("ShadowPeople");
        for (int i = 0; i < allObjects.Length; i++)
        {
            if (Vector3.Distance(allObjects[i].transform.position, transform.position) >
                                                     radiusDetection)
            {
                listOfAllAwayShadow.Add(allObjects[i]);
            }
        }
        return listOfAllAwayShadow;
    }
    private void SpawnEnemy()
    {
        if (Time.time > spawnMeleeNext && !maxreached)
        {
            spawnMeleeNext = Time.time + spawnMeleeRate;
            Vector3 spawnPos = GameObject.Find("Player").transform.position; //Spawning an enemy
            spawnPos.x += Random.insideUnitSphere.x * radiusDetection;
            spawnPos.z += Random.insideUnitSphere.z * radiusDetection;
            if(timerToSuicide > 10)
            {
                Instantiate(shadowPeoplePrefab, spawnPos, Quaternion.identity);
                currentEnemy+=1;
            }
            else if (timerToSuicide <= 10)
            {
                Instantiate(shadowPeopleInsaneModePrefab, spawnPos, Quaternion.identity);
                currentEnemy += 1;
            }
        }

        foreach (GameObject shadow in listOfAllAwayShadow)
        {
            Vector3 spawnPos = GameObject.Find("Player").transform.position; //Spawning an enemy
            spawnPos.x += Random.insideUnitSphere.x * radiusDetection;
            spawnPos.z += Random.insideUnitSphere.z * radiusDetection;
            DestroyObject(shadow);
            currentEnemy=-1;

            if (listOfAllNearbyShadow.Count < enemyMax && !maxreached)
            {
                if (timerToSuicide > 10)
                {
                    Instantiate(shadowPeoplePrefab, spawnPos, Quaternion.identity);
                    currentEnemy += 1;
                }
                else if (timerToSuicide <= 10)
                {
                    Instantiate(shadowPeopleInsaneModePrefab, spawnPos, Quaternion.identity);
                    currentEnemy += 1;
                }
            }
        }
    }

    IEnumerator DestroyWithTag(string destroyTag)
    {
        GameObject[] shadowPeople;
        shadowPeople = GameObject.FindGameObjectsWithTag(destroyTag);
        foreach (GameObject oneObject in shadowPeople)
            Destroy(oneObject);
        yield return new WaitForSeconds(1);
    }


    public void OnShadow()
    {
        _surroundedLight = false;
    }

    public void OutShadow()
    {
        _surroundedLight = true;
    }
    private void OnDrawGizmosSelected()
    {
        Gizmos.color = Color.yellow;
        Gizmos.DrawWireSphere(transform.position, radiusDetection);
    }

    public void LoadData(GameData data)
    {
        this.currentFear = data.fearLevel;
        this.timerToSuicide = data.sanityLevel;
    }

    public void SaveData(GameData data)
    {
        data.fearLevel = this.currentFear;
        data.sanityLevel = this.timerToSuicide;
    }
}