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

[DisallowMultipleComponent]
public class Level : MonoBehaviour
{
    private enum GameState
    {
        Start,
        Finished,
        GameOver,
        None
    }
    
    public GameObject m_marblePrefab;
    public Text m_pointsText;
    public GameObject m_background;
    public Text m_gameOverText;
    public Text m_finishedText;
    public AudioClip m_gameOverSound;
    public AudioClip m_finishSound;
    public AudioClip m_itemCollectSound;
    
    private GameObject m_startPosition;
    private FinishPosition m_finishPosition;
    private GameObject m_marbleInstance;
    private AudioSource m_audioSource;
    private Vector3 m_cameraOffset = new Vector3(0.0f, 15.0f, -15.0f);
    private Rigidbody m_marbleRigidBody;
    private Joystick m_joystick;
    private float m_forceMultiplier = 100.0f;
    private GameState m_gameState = GameState.None;
    private int m_pointsCollected = 0;

    public void LoadMainMenu()
    {
        SceneManager.LoadScene("Menu", LoadSceneMode.Single);
    }
    
    public void RestartLevel()
    {
        SceneManager.LoadScene(gameObject.scene.name, LoadSceneMode.Single);
    }
    
    // Start is called before the first frame update
    private void Start()
    {
        m_audioSource = GetComponent<AudioSource>();
        m_startPosition = GameObject.FindGameObjectWithTag("StartPosition");
        m_finishPosition = FindObjectOfType<FinishPosition>();
        m_joystick = FindObjectOfType<Joystick>();
        
        SetGameState(GameState.Start);

        var electricShocks = FindObjectsOfType<ElectricShock>();

        for (int i = 0; i < electricShocks.Length; i++)
        {
            electricShocks[i].OnCollision += _ =>
            {
                SetGameState(GameState.GameOver);
            };
        }
        
        var items = FindObjectsOfType<Item>();

        for (int i = 0; i < items.Length; i++)
        {
            items[i].OnCollision += _ =>
            {
                m_audioSource.PlayOneShot(m_itemCollectSound);
                m_pointsCollected += 1;
                UpdatePoints();
            };
        }

        m_finishPosition.OnCollision += go =>
        {
            if (go == m_marbleInstance)
            {
                SetGameState(GameState.Finished);
            }
        };
        
        UpdatePoints();
    }
    
    private void FixedUpdate()
    {
        CheckForGameOver();
        
        var joystickDirectionNormalized = m_joystick.GetNormalizedDirection();
        
        var force = new Vector3(joystickDirectionNormalized.x * m_forceMultiplier, 0.0f, joystickDirectionNormalized.y * m_forceMultiplier);
        force *= Time.deltaTime;
        m_marbleRigidBody.AddForce(force);
    }

    private void SetGameState(GameState _newState)
    {
        if (_newState == m_gameState)
        {
            return;
        }

        m_gameState = _newState;
        
        switch (_newState)
        {
            case GameState.Start:
                OnGameStateStart();
                break;
            
            case GameState.GameOver:
                OnGameStateGameOver();
                break;
            
            case GameState.Finished:
                OnGameStateFinished();
                break;
        }
    }

    private void OnGameStateStart()
    {
        m_marbleInstance = Instantiate(m_marblePrefab);
        m_marbleInstance.transform.position = m_startPosition.transform.position;
        m_marbleRigidBody = m_marbleInstance.GetComponent<Rigidbody>();
    }
    
    private void CheckForGameOver()
    {
        if (m_marbleInstance != null)
        {
            var cameraTransform = Camera.main.transform;
            
            cameraTransform.position = m_marbleInstance.gameObject.transform.position + m_cameraOffset;
            cameraTransform.LookAt(m_marbleInstance.transform.position);

            if (m_marbleRigidBody.gameObject.transform.position.y < -20.0f)
            {
                SetGameState(GameState.GameOver);
            }   
        }
    }
    
    private void OnGameStateGameOver()
    {
        OnEndGame(false);
    }

    private void OnGameStateFinished()
    {
        OnEndGame(true);
    }

    private void OnEndGame(bool _levelWon)
    {
        m_marbleRigidBody.constraints = RigidbodyConstraints.FreezeAll;

        m_finishedText.gameObject.SetActive(_levelWon);
        m_gameOverText.gameObject.SetActive(!_levelWon);
        m_background.SetActive(true);
        
        m_joystick.gameObject.transform.parent.gameObject.SetActive(false);

        m_audioSource.PlayOneShot(_levelWon ? m_finishSound : m_gameOverSound);
        
        UpdateHighscore();
    }

    private void UpdatePoints()
    {
        m_pointsText.text = string.Format("Points: {0}", m_pointsCollected);
    }

    private void UpdateHighscore()
    {
        var highscore = PlayerPrefs.GetInt("player_highscore", 0);

        if (m_pointsCollected > highscore)
        {
            PlayerPrefs.SetInt("player_highscore", m_pointsCollected);
        }
    }
}
