using System;
using System.Collections;
using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;

enum GameState
{
  START_MENU,
  GAME_RUNNING,
  GAME_FINISHED,
}

public class GameManager : MonoBehaviour
{

  public GameObject player;

  private GameState gameState;

  private int points = 0;

  // Game
  [Header("Game Settings")]
  public float gameDuration = 30.0f;
  private float gameTimeRemaining = 0;
  private bool allowTargetSpawn = false;

  #region Target spawning variables
  [Header("Target Spawning")]
  public GameObject targetPrefab;
  public int numberOfTargets = 3;
  public float targetSpawnDelay = 1.0f;
  public float targetMoveSpeed = 1.0f;
  public float targetWaitTime = 1.0f;

  public int targetMinPoint = 1;
  public int targetMaxPoint = 1;


  public float targetSpawnMinDistance = 1.0f;
  public float targetSpawnMaxDistance = 1.0f;
  public float targetSpawnMinHeight = 1.0f;
  public float targetSpawnMaxHeight = 1.0f;
  public float targetSpawnAngle = 90;

  public float targetMovePointMinDistance = 1.0f;
  public float targetMovePointMaxDistance = 1.0f;
  #endregion

  #region HUD
  [Header("HUD")]
  public TextMeshPro pointsHud;
  public TextMeshPro timeRemainingHud;

  public GameObject startMenu;
  public GameObject endMenu;
  #endregion


  // Start is called once before the first execution of Update after the MonoBehaviour is created
  void Start()
  {
    StartMenuGame();
  }

  // Update is called once per frame
  void Update()
  {
    switch (gameState) {
      case GameState.START_MENU:

        break;
      case GameState.GAME_RUNNING:
        gameTimeRemaining -= Time.deltaTime;


        if (gameTimeRemaining <= 0)
        {
          gameTimeRemaining = 0;
          EndGame();
        }

        timeRemainingHud.text = (Mathf.Floor(gameTimeRemaining * 100) / 100).ToString();

        break;
      case GameState.GAME_FINISHED:
        
        break;
      default:
        break;
    }
  }

  public void StartMenuGame()
  {
    gameState = GameState.START_MENU;

    startMenu.SetActive(true);
    endMenu.SetActive(false);
  }

  
  public void StartGame()
  {
    gameState = GameState.GAME_RUNNING;
    gameTimeRemaining = gameDuration;
    SetPoints(0);
    allowTargetSpawn = true;

    startMenu.SetActive(false);
    endMenu.SetActive(false);

    for (int i = 0; i < numberOfTargets; i++)
    {
      SpawnTarget();
    }
  }


  private void EndGame()
  {






    gameState = GameState.GAME_FINISHED;
    allowTargetSpawn = false;

    startMenu.SetActive(false);
    endMenu.SetActive(true);

    GameObject[] targets = GameObject.FindGameObjectsWithTag("Target");

    foreach(GameObject Target in targets)
    {
      Destroy(Target);
    }

    //Display End screen, give possibility to go back to start menu
  }

  private IEnumerator SpawnTargetDelay(float delay)
  {
    yield return new WaitForSeconds(delay);

    SpawnTarget();

  }

  private void SpawnTarget()
  {

    if (!allowTargetSpawn)
    {
      return;
    }

    Debug.Log("Spawning target...");
    //Determine target spawn position
    float spawnAngle = Random.Range(-targetSpawnAngle/2,targetSpawnAngle/2);
    float spawnDistance = Random.Range(targetSpawnMinDistance, targetSpawnMaxDistance);
    float spawnHeight = Random.Range(targetSpawnMinHeight, targetSpawnMaxHeight);

    spawnAngle = spawnAngle * Mathf.Deg2Rad;


    Vector3 spawnPosition = new Vector3(
      player.transform.position.x + Mathf.Sin(spawnAngle) * spawnDistance,
      player.transform.position.y + spawnHeight,
      player.transform.position.z + Mathf.Cos(spawnAngle) * spawnDistance
    );

    //Determine target target position
    float targetMovePointDistance = Random.Range(targetMovePointMinDistance, targetMovePointMaxDistance);


    Vector3 randomDirection = Random.onUnitSphere;

    Vector3 targetMovePosition = spawnPosition + randomDirection * targetMovePointDistance;


    Debug.Log(randomDirection);
    Debug.Log("Intended move distance: " + targetMovePointDistance);
    Debug.Log("Actual distance: " + (spawnPosition - targetMovePosition).magnitude);



    GameObject spawnedTarget = Instantiate(targetPrefab);
    spawnedTarget.transform.position = spawnPosition;
    Target spawnedTargetScript = spawnedTarget.GetComponent<Target>();

    if (spawnedTargetScript != null)
    {
      spawnedTargetScript.SetValue(targetMoveSpeed, targetWaitTime, Random.Range(targetMinPoint, targetMaxPoint+1), targetMovePosition, this);
    }

    Debug.Log("Spawn Target, distance: " + (player.transform.position - spawnedTarget.transform.position).magnitude);
  }

  private void SetPoints(int Points)
  {
    points = Points;
    pointsHud.text = points.ToString();
  }

  private void AddPoints(int Points)
  {
    points += Points;
    pointsHud.text = points.ToString();
  }

  public void NotifyTargetDestroyed(Target Target)
  {

    AddPoints(Target.points);
    StartCoroutine(SpawnTargetDelay(targetSpawnDelay));

    Destroy(Target.gameObject);
  }
}
