using UnityEngine;
using System.Collections;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameManager : MonoBehaviour {
    public GameObject gameOverPanel;
    public Text goScore;
    public Text goHighscore;
    
    public Image[] soundPilot;
    public AudioSource audioSource;

    public GameObject[] ships;
    public Text scoreText;

    public float playerHealth = 100;
    public Image healthBar;
    public GameObject playerDeathEffect;

    public Image[] shiftBits;
    public float shiftChargeTime = 5f;
    public float shiftExplodeTime = 5f;
    public GameObject shiftExplosion;

    public GameObject pausePanel;
    public Text pauseIndicator;

    public Text txtGlobalControl;
    public Text txtLocalControl;

    [SerializeField]
    int score = 0;

    [SerializeField]
    float health = 100;

    float scoreTextCD = 0;

    int shipID = -1;
    GameObject _player;
    float shiftCount = 0;

    float wobbleCD = 0;
    Vector2 wobbleOffset = Vector2.zero;
    Vector3 CameraPosition;

    [SerializeField]
    bool paused = false;
        
    Color color_shift_empty;
    Color color_shift_charged;
    Color color_shift_explode;
    
    const float _WOBBLE_TIME_ = 0.3f;
    const float _WOBBLE_WIDTH_ = 0.05f; 
    const float _MAX_WIDTH_ = 128f;

    void Awake()
    {
        Random.seed = System.DateTime.Now.Millisecond * System.DateTime.Now.Second * System.DateTime.Now.Minute;
    }

    void Start()
    {
        _player = GameObject.FindGameObjectWithTag("Player");
        CameraPosition = Camera.main.transform.position;
        DisableAll(false);
        FindObjectOfType<AudioManager>().enabled = true;

        // Reset Score Text
        scoreText.text = score.ToString();

        // Reset current health (player Health --> max health)
        health = playerHealth;

        // Define Shift Colors
        color_shift_empty = new Color(0.27f, 1, 1, 0.2f);
        color_shift_charged = new Color(0.27f, 1, 1,1);
        color_shift_explode = new Color(1, 0.27f, 0.27f, 1);

        // Reset Shift indicator
        int index = Mathf.FloorToInt(shiftCount * shiftBits.Length / shiftChargeTime);
        foreach (Image s in shiftBits)
            s.color = Color.Lerp(color_shift_empty, color_shift_charged, (shiftCount * shiftBits.Length / shiftChargeTime) - index);

        // Set Sound Prefs
        if (PlayerPrefs.GetInt("audio",1) == 1)
        {
            audioSource.volume = 0.25f;
            soundPilot[0].enabled = false;
            soundPilot[1].enabled = true;
        }
        else
        {
            audioSource.volume = 0;
            soundPilot[1].enabled = false;
            soundPilot[0].enabled = true;
        }

        //Assign random ship
        shipID = Random.Range(0, ships.Length);
        Shift();

        ChangeControl();
        ChangeControl();
    }

    void Update()
    {
        if (scoreTextCD < 0.7f)
        {
            scoreText.text = Mathf.FloorToInt( Mathf.Lerp(int.Parse(scoreText.text), score, 2f * scoreTextCD) ).ToString();
            scoreTextCD += Time.deltaTime;
        }

        if (Input.GetButtonDown("Pause") || Input.GetButtonDown("Cancel"))
        {
            DisableAll(!paused);
            pausePanel.SetActive(paused);

            if (paused)
            {
                pauseIndicator.text = "enabled";
                pauseIndicator.color = new Color(0.27f, 1, 0.27f, 1);
            }
            else
            {
                pauseIndicator.text = "disabled";
                pauseIndicator.color = new Color(1, 0.27f, 0.27f, 1);
            }
        }

        if (!paused)
        {
            // CAMERA WOBBLE ON HIT
            if (wobbleCD > 0)
            {
                Camera.main.transform.position = new Vector3(
                    _WOBBLE_WIDTH_ * Mathf.Sin(wobbleOffset.x + wobbleCD * 6 * Mathf.PI / _WOBBLE_TIME_),
                    _WOBBLE_WIDTH_ * Mathf.Sin(wobbleOffset.y + wobbleCD * 6 * Mathf.PI / _WOBBLE_TIME_),
                    Camera.main.transform.position.z
                    );

                wobbleCD -= Time.deltaTime;

                if (wobbleCD <= 0) Camera.main.transform.position = CameraPosition;
            }

            // UPDATE SHIT INDICATOR
            shiftCount += Time.deltaTime;

            if (shiftCount < shiftChargeTime)
            {
                int index = Mathf.FloorToInt(shiftCount * shiftBits.Length / shiftChargeTime);
                shiftBits[index].color = Color.Lerp(color_shift_empty, color_shift_charged, (shiftCount * shiftBits.Length / shiftChargeTime) - index);
            }
            else if (shiftCount >= shiftChargeTime && shiftCount < shiftChargeTime + shiftExplodeTime)
            {
                int index = Mathf.FloorToInt((shiftCount - shiftChargeTime) * shiftBits.Length / shiftExplodeTime);
                shiftBits[index].color = Color.Lerp(color_shift_charged, color_shift_explode, ((shiftCount - shiftChargeTime) * shiftBits.Length / shiftExplodeTime) - index);
            }
            else ActivateShiftDrive();
        }

        if (Input.GetKeyDown(KeyCode.M))
        {
            if (audioSource.volume == 0)
            {
                audioSource.volume = 0.25f;
                soundPilot[0].enabled = false;
                soundPilot[1].enabled = true;
                PlayerPrefs.SetInt("audio", 1);
            }
            else
            {
                audioSource.volume = 0;
                soundPilot[1].enabled = false;
                soundPilot[0].enabled = true;
                PlayerPrefs.SetInt("audio", 0);
            }
        } 

        if (Input.GetKeyDown(KeyCode.C))
        {
            ChangeControl();
        }
    }

    public void GameOver()
    {
        // IF GAME OVER, DESTROY ANY OBJECTS ON SCREEN AND STOP SPAWNING NEW OBJECTS
        DisableAll(true);

        // SHOW GAME OVER SCREEN
        gameOverPanel.SetActive(true);
        goScore.text = "Score: " + score.ToString();

        int highscore = PlayerPrefs.GetInt("highscore", 0);
        if (score > highscore) PlayerPrefs.SetInt("highscore", score);

        goHighscore.text = "Highscore: " + PlayerPrefs.GetInt("highscore", score);

        FindObjectOfType<AudioManager>().enabled = false;
    }

    public void LoadLevel(string name)
    {
        SceneManager.LoadScene(name);
    }

    public void Shift()
    {
        int newID = Random.Range(0, ships.Length - 1); // Random exclude current id
        if (newID >= shipID) newID++; // compensate for current id

        if (_player != null)
            Destroy(_player);

        _player = (GameObject)Instantiate(ships[newID], _player.transform.position, _player.transform.rotation);
        shipID = newID;
    }

    public void IncreaseScore(int points)
    {
        score += points;
        //scoreText.text = score.ToString();
        scoreTextCD = 0;
    }

    public void DamagePlayer(float damage)
    {
        health -= damage;

        if (health <= 0)
        {
            healthBar.rectTransform.sizeDelta = new Vector2(0, healthBar.rectTransform.rect.height);
            if (playerDeathEffect != null)
            {
                GameObject d = (GameObject)Instantiate(playerDeathEffect, this.transform.position, this.transform.rotation);
                d.name = "Explosion";
            }
            GameOver();
        }
        else {
            UpdateHealthbar();
            if (wobbleCD <= 0)
            {
                wobbleCD = _WOBBLE_TIME_;
                wobbleOffset = new Vector2(Random.Range(-3f, 3f), Random.Range(-3f, 3f));
            }
        }
    }

    void UpdateHealthbar ()
    {
        healthBar.rectTransform.sizeDelta = new Vector2(_MAX_WIDTH_ * health / playerHealth, healthBar.rectTransform.rect.height);
    }

    public void ActivateShiftDrive()
    {
        if (_player == null) return;
        shiftCount = 0;

        // Reset Shift indicator
        int index = Mathf.FloorToInt(shiftCount * shiftBits.Length / shiftChargeTime);
        foreach (Image s in shiftBits)
            s.color = Color.Lerp(color_shift_empty, color_shift_charged, (shiftCount * shiftBits.Length / shiftChargeTime) - index);

        // EXPLODE
        GameObject e = (GameObject)Instantiate(shiftExplosion, _player.transform.position, _player.transform.rotation);
        e.name = "ShiftExplosion";

        // WOBBLE
        wobbleCD = 1.5f * _WOBBLE_TIME_;
        wobbleOffset = new Vector2(Random.Range(-3f, 3f), Random.Range(-3f, 3f));

        Shift();
    }

    public bool isShiftEnabled()
    {
        return (shiftCount >= shiftChargeTime);
    }

    void DisableAll(bool state)
    {
        paused = state;

        Explosion[] es = FindObjectsOfType<Explosion>();
        foreach (Explosion e in es) e.enabled = !state;

        Player pj = FindObjectOfType<Player>();
        if (pj != null) pj.enabled = !state;

        Character[] cs = FindObjectsOfType<Character>();
        foreach (Character c in cs) c.enabled = !state;

        Projectile[] ps = FindObjectsOfType<Projectile>();
        foreach (Projectile p in ps)
        {
            AudioSource _as = p.gameObject.GetComponent<AudioSource>();
            if (_as != null) _as.enabled = !state;
            p.enabled = !state;
        }

        Enemy[] ens = FindObjectsOfType<Enemy>();
        foreach (Enemy e in ens) e.enabled = !state;

        SpawnManager spw = FindObjectOfType<SpawnManager>();
        if (spw != null) spw.enabled = !state;
    }

    public void ChangeControl()
    {
        if (PlayerPrefs.GetInt("control", 0) == 1)
        {
            txtGlobalControl.color = new Color(0.27f,1,0.27f,1);
            txtLocalControl.color = new Color(1, 0.27f, 0.27f, 1);
            PlayerPrefs.SetInt("control", 0);
            FindObjectOfType<Player>().directControl = false;
        }
        else
        {
            txtGlobalControl.color = new Color(1, 0.27f, 0.27f, 1);
            txtLocalControl.color = new Color(0.27f, 1, 0.27f, 1);
            PlayerPrefs.SetInt("control", 1);
            FindObjectOfType<Player>().directControl = true;
        }
    }

    public void Resume()
    {
        DisableAll(false);
        pausePanel.SetActive(false);
        pauseIndicator.text = "disabled";
        pauseIndicator.color = new Color(1, 0.27f, 0.27f, 1);
    }
}
