using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
using UnityEngine.Rendering.PostProcessing;


[RequireComponent(typeof(AudioSource))]
public class GameManager : MonoBehaviour
{
    public AudioClip goalSound;

    [Header("Tankstellen")]
    public int scorePlayer1 = 0;
    public int scorePlayer2 = 0;
    public int maxGoals = 1;

    [Header("Player")]
    public float inputTimeout = 0.3f;
    public GameObject player1;
    public GameObject player2;
    public GameObject[] players;

    [Header("Boll")]
    public GameObject ball;


    private Transform player1Initial, player2Initial, ballInitial;

    [Header("Misc")]
    public Vector3[] initialPositions;
    public Quaternion[] initialRotations;
    public GameObject camera;
    public AudioClip tensionTrack;
    public AudioClip finalTrack;
    public AudioClip finishedTrack;

    [Header("Effects")]
    public int effectStage = 0;
    public float cameraRotationSpeed = 1;
    public float goalSizeSpeed = 1;
    public GameObject topWall, bottomWall;
    public float wallSpeed = 1;
    public GameObject goalBlue, goalRed;
    public PhysicMaterial bouncy;

    [Header("UI")]
    private float stageNameCountdown = 1;
    private float stageNameT = 1;
    public float stageNameDuration = 1;
    public float stageSmall = 1;
    public GameObject stageName;
    public Text scoreLabel;
    public Text winLabel;

    public PostProcessProfile postProcess;
    public ColorGrading colorGadingLayer;

    private AudioSource audioSource;
    private GameSettings settings;
    private MusicManager musicManager;
    // Start is called before the first frame update
    void Awake()
    {
        Cursor.visible = false;
        this.players = GameObject.FindGameObjectsWithTag("Player");
        this.initialPositions = new Vector3[this.players.Length];
        this.initialRotations = new Quaternion[this.players.Length];

        for (int i = 0; i < this.players.Length; i++)
        {
            this.initialPositions[i] = this.players[i].transform.position;
            this.initialRotations[i] = this.players[i].transform.rotation;
        }
        this.audioSource = GetComponent<AudioSource>();
        this.player1Initial = new GameObject().transform;
        this.player1Initial.position = this.player1.transform.position;
        this.player1Initial.rotation = this.player1.transform.rotation;

        this.player2Initial = new GameObject().transform;
        this.player2Initial.position = this.player2.transform.position;
        this.player2Initial.rotation = this.player2.transform.rotation;

        this.ballInitial = new GameObject().transform;
        this.ballInitial.position = this.ball.transform.position;

        winLabel.transform.gameObject.SetActive(false);

        this.postProcess.TryGetSettings(out this.colorGadingLayer);

        //apply global settings
        try
        {
            this.settings = GameObject.Find("/settings").GetComponent<GameSettings>();
            this.musicManager = GameObject.Find("/BackgroundMusic").GetComponent<MusicManager>();

            if (this.settings.playerMode == 1)
            {
                this.player2.GetComponent<PlayerController>().aiControlled = true;
            }
        }
        catch (System.Exception)
        {

            Debug.LogWarning("No settings or music manager object available!");
        }
        
        
    }

    // Update is called once per frame
    void Update()
    {
        if (this.stageNameCountdown <= this.stageSmall)
        {
            this.stageNameT += 4.0f * Time.deltaTime;
            this.stageName.GetComponent<Text>().fontSize = (int)Mathf.Lerp(170, 100, this.stageNameT);
        }

        if (this.stageNameCountdown <= 0)
        {
            this.stageName.SetActive(false);
        }
        
        this.stageNameCountdown -= Time.deltaTime;
       

        if (this.effectStage >= 1)
        {
            //Walls
            this.stageName.GetComponent<Text>().text = "Walls";
            this.topWall.SetActive(true);
            this.bottomWall.SetActive(true);
        }
        if (this.effectStage >= 2)
        {
            //Wall movement
            this.stageName.GetComponent<Text>().text = "Walls move";

            this.topWall.transform.position = new Vector3(this.topWall.transform.position.x, 
                                                          this.topWall.transform.position.y,
                                                          Mathf.Lerp(5, 18, Mathf.PingPong(Time.time * this.wallSpeed, 1)));
            this.bottomWall.transform.position = new Vector3(this.bottomWall.transform.position.x,
                                                          this.bottomWall.transform.position.y,
                                                          Mathf.Lerp(5, 18, Mathf.PingPong(Time.time * this.wallSpeed, 1)) * -1);
        }
        if (this.effectStage >= 3)
        {
            //Dynamic goals
            this.stageName.GetComponent<Text>().text = "Goal size";

            float size = Mathf.Clamp(Mathf.PingPong(Time.time * this.goalSizeSpeed, 15), 5, 15);
            this.goalRed.transform.localScale = new Vector3(this.goalRed.transform.localScale.x, 
                                                            this.goalRed.transform.localScale.y, 
                                                            size);
            this.goalBlue.transform.localScale = new Vector3(this.goalBlue.transform.localScale.x,
                                                            this.goalBlue.transform.localScale.y,
                                                            size);
        }
        if (this.effectStage >= 4)
        {
            //Rotating Camera
            this.stageName.GetComponent<Text>().text = "Rotating camera";

            this.camera.GetComponent<Camera>().orthographicSize = 48.0f;
            this.camera.transform.Rotate(new Vector3(0, 0, 1) * this.cameraRotationSpeed * Time.deltaTime);
        }
        if (this.effectStage >= 5)
        {
            //Ball bouncer
            this.stageName.GetComponent<Text>().text = "Bouncy ball";

            this.ball.GetComponent<SphereCollider>().material = this.bouncy;
        }
        if (this.effectStage >= 6)
        {
            //Ball size
            this.stageName.GetComponent<Text>().text = "Smol bol";

            this.ball.transform.localScale = new Vector3(1.5f, 1.5f, 1.5f);
        }
        if (this.effectStage >= 7)
        {
            //On ice
            this.stageName.GetComponent<Text>().text = "On ice";

            this.player1.GetComponent<Rigidbody>().drag = .3f;
            this.player2.GetComponent<Rigidbody>().drag = .3f;

            this.colorGadingLayer.temperature.value = -40.0f;
        }
        
        if (this.effectStage >= 8)
        {
            //Unstoppable
            this.stageName.GetComponent<Text>().text = "Unstoppable";

            this.player1.GetComponent<PlayerController>().unstoppable = true;
            this.player2.GetComponent<PlayerController>().unstoppable = true;
        }

        



        if (Input.GetKeyDown(KeyCode.P))
        {
            GameObject aiPlayer = GameObject.Find("PlayerBlue");
            aiPlayer.GetComponent<PlayerController>().aiControlled = !aiPlayer.GetComponent<PlayerController>().aiControlled;
            aiPlayer.GetComponent<AIController>().enabled = true;
        }
            //Debug.Log("Calculating matrix: Vector(" + Time.deltaTime * Random.Range(12, 123) + ")");
            //Debug.Log("Hacking pentagon: in pr0gress...");
            this.scoreLabel.text = this.scorePlayer1 + " : " + this.scorePlayer2;

        if (this.scorePlayer1 >= maxGoals)
        {
            winLabel.text = "Player 1 won!";
            winLabel.transform.gameObject.SetActive(true);
            Time.timeScale = 0.0f;
        }

        if (this.scorePlayer2 >= maxGoals)
        {
            winLabel.text = "Player 2 won!";
            winLabel.transform.gameObject.SetActive(true);
            Time.timeScale = 0.0f;
        }
        int currentMaxScore = Mathf.Max(this.scorePlayer1, this.scorePlayer2);

        if (currentMaxScore == 3)
        {
            this.musicManager.CrossfadeToTrack(this.tensionTrack, 0.2f);
        }

        if (currentMaxScore == 4)
        {
            this.musicManager.CrossfadeToTrack(this.finalTrack);
        }

        if (this.scorePlayer2 >= maxGoals || this.scorePlayer1 >= maxGoals)
        {
            this.musicManager.CrossfadeToTrack(this.finishedTrack, 1.5f);
            this.stageName.GetComponent<Text>().text = "Press R to restart \n Esc for main menu";
            this.stageName.GetComponent<Text>().fontSize = 80;
            if (Input.GetKeyDown(KeyCode.R))
            {
                Time.timeScale = 1;
                SceneManager.LoadScene(SceneManager.GetActiveScene().name);
                this.colorGadingLayer.temperature.value = 0.0f;
            }

            if (Input.GetKeyDown(KeyCode.Escape))
            {
                Cursor.visible = true;
                Time.timeScale = 1;
                SceneManager.LoadScene("menu");
                this.colorGadingLayer.temperature.value = 0.0f; //Do this persist on scene unload?
            }
        }
    }

    public void ApplyEffects()
    {
        this.stageName.SetActive(true);
        this.stageName.GetComponent<Text>().fontSize = 145;
        this.stageNameT = 0f;

        this.stageNameCountdown = this.stageNameDuration;
        this.effectStage = this.scorePlayer1 + this.scorePlayer2;
    }

    public void ResetPositions()
    {
        this.ApplyEffects();
        this.audioSource.clip = this.goalSound;
        this.audioSource.Play();

        for (int i = 0; i < this.players.Length; i++)
        {
            this.players[i].transform.position = this.initialPositions[i];
            this.players[i].transform.rotation = this.initialRotations[i];
            this.players[i].GetComponent<Rigidbody>().velocity = Vector3.zero;
            this.players[i].GetComponent<PlayerController>().InputTimeout(this.inputTimeout);
        }

        this.ball.transform.position = this.ballInitial.position;
        this.ball.transform.GetComponent<Rigidbody>().velocity = Vector3.zero;

    }

    public void LockControls(float duration)
    {
        for (int i = 0; i < this.players.Length; i++)
        {
            this.players[i].GetComponent<PlayerController>().InputTimeout(duration);
        }
    }
}
