using RetroDev.Random;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;

/// <summary>
/// Manages the spawning of waves, including players, obstacles, and enemies.
/// </summary>
public class WaveManager : MonoBehaviour
{
    [Header("Spawn Customization")]
    public GameObject playerPrefab; // Prefab for the player object
    public GameObject[] obstaclePrefabs; // Array of obstacle prefabs
    public GameObject[] enemyPrefabs; // Array of enemy prefabs
    public GameObject gameCanvas; // Reference to the game canvas

    [Header("Wave Customization")]
    public int initialWaveEnemyCount = 1; // Initial number of enemies in the first wave
    public static int currentWave = 1; // Current wave number
    public int maxEnemiesPerWave = 4; // Maximum number of enemies per wave
    public float enemySpawnDelay = 2f; // Delay between enemy spawns
    public int numberOfObstacles = 1; // Number of obstacles to spawn per wave

    public static WaveManager instance; // Singleton instance of WaveManager

    /// <summary>
    /// Initializes the singleton instance.
    /// </summary>
    private void Awake()
    {
        instance = this;

        playerPrefab = ShapeSelect.selectedShape;
    }

    /// <summary>
    /// Starts the first wave of the game.
    /// </summary>
    private void Start()
    {
        if (Loader.fromMenu)
        {
            // Reset game attributes and metrics
            ScoreManager.instance.score = 0;
            currentWave = 1;
            Performance.shotsFired = 0;
            Performance.damageDealt = 0;
            Performance.shipsDestroyed = 0;
            currentWave = 1;

            // Reset the toggle
            Loader.fromMenu = false;    
        }

        if (Reset.instance.player != null)
        {
            // Start the first wave
            StartWave();
        }
        else
        {
            Invoke(nameof(StartWave), 2f);
        }
    }

    /// <summary>
    /// Initiates the spawning and setup of a new wave.
    /// </summary>
    public void StartWave()
    {
        // Show wave start text
        UIManager.Instance.ShowWaveText();

        // Show random quote
        WaveQuotes.instance.ShowQuote();

        // Spawn player
        SpawnPlayer();

        // Spawn obstacles
        SpawnObstacles();

        // Spawn enemies for the current wave
        Invoke(nameof(SpawnEnemies), enemySpawnDelay);

        // Subscribe to enemy destruction event
        Enemy.OnEnemyDestroyed += HandleEnemyDestroyed;
    }

    /// <summary>
    /// Handles the event when an enemy is destroyed.
    /// </summary>
    private void HandleEnemyDestroyed()
    {
        // Check if all enemies for the current wave are destroyed
        if (Enemy.GetEnemyCount() == 0)
        {
            // Unsubscribe from the enemy destruction event
            Enemy.OnEnemyDestroyed -= HandleEnemyDestroyed;

            // Destroy player and obstacles
            DestroyPlayer();
            DestroyObstacles();

            // Show upgrade overlay after a delay
            Invoke(nameof(ShowUpgradeOverlay), 1f);
        }
    }

    /// <summary>
    /// Displays the upgrade overlay for the player after completing a wave.
    /// </summary>
    public void ShowUpgradeOverlay()
    {
        AudioManager.instance.MuffleAudio();

        // Show upgrades menu after completing a wave
        UIManager.Instance.waveCompleteOverlay.SetActive(true);
    }

    /// <summary>
    /// Starts the next wave after the current wave is completed.
    /// </summary>
    public void StartNextWave()
    {
        // Play sound effect
        AudioManager.instance.PlayClickSound();

        AudioManager.instance.UnmuffleAudio();

        // Hide upgrades menu
        UIManager.Instance.waveCompleteOverlay.SetActive(false);

        // Start next wave after a delay
        StartCoroutine(StartNextWaveAfterDelay(1f));
    }

    /// <summary>
    /// Coroutine to start the next wave after a delay.
    /// </summary>
    private IEnumerator StartNextWaveAfterDelay(float delay)
    {
        yield return new WaitForSeconds(delay);

        // Increment current wave and start the next wave
        currentWave++;
        StartWave();
    }

    /// <summary>
    /// Spawns the player character.
    /// </summary>
    private void SpawnPlayer()
    {
        Vector2 playerSpawnPosition = RandomUtil.RandomVector2D(BoundaryManager.instance.MinBounds, BoundaryManager.instance.MaxBounds);

        // Destroy existing player if any
        DestroyPlayer();

        // Instantiate player under the game canvas
        Instantiate(playerPrefab, playerSpawnPosition, Quaternion.identity, gameCanvas.transform);

        // Reset player attributes (disabled for now)
        // Reset.instance.ResetGame();
    }

    /// <summary>
    /// Destroys the player character if it exists.
    /// </summary>
    private void DestroyPlayer()
    {
        // Find and destroy existing player in the scene
        PlayerController existingPlayer = FindObjectOfType<PlayerController>();
        if (existingPlayer != null)
        {
            Destroy(existingPlayer.gameObject);
        }
    }

    /// <summary>
    /// Destroys all existing obstacles in the scene.
    /// </summary>
    private void DestroyObstacles()
    {
        // Find and destroy all existing obstacles in the scene
        GameObject[] existingObstacles = GameObject.FindGameObjectsWithTag("Obstacle");
        foreach (var obstacle in existingObstacles)
        {
            Destroy(obstacle.gameObject);
        }
    }

    /// <summary>
    /// Spawns obstacles based on the specified number and type.
    /// </summary>
    private void SpawnObstacles()
    {
        for (int i = 0; i < numberOfObstacles; i++)
        {
            Vector2 obstacleSpawnPosition = RandomUtil.RandomVector2D(BoundaryManager.instance.MinBounds, BoundaryManager.instance.MaxBounds);
            int obstacleIndex = RandomUtil.RandomNumber(0, obstaclePrefabs.Length);

            // Instantiate obstacle under the game canvas
            Instantiate(obstaclePrefabs[obstacleIndex], obstacleSpawnPosition, RandomUtil.RandomRotation2D(), gameCanvas.transform);
        }
    }

    /// <summary>
    /// Spawns enemies for the current wave.
    /// </summary>
    private void SpawnEnemies()
    {
        // Randomize the number of enemies for the current wave
        int numberOfEnemies = Random.Range(1, Mathf.Min(initialWaveEnemyCount + currentWave, maxEnemiesPerWave + 1));

        for (int i = 0; i < numberOfEnemies; i++)
        {
            Vector2 enemySpawnPosition = RandomUtil.RandomVector2D(BoundaryManager.instance.MinBounds, BoundaryManager.instance.MaxBounds);
            int enemyIndex = RandomUtil.RandomNumber(0, enemyPrefabs.Length);

            // Instantiate enemy under the game canvas
            Instantiate(enemyPrefabs[enemyIndex], enemySpawnPosition, Quaternion.identity, gameCanvas.transform);
        }
    }

    /// <summary>
    /// Starts a new game, resetting game attributes and metrics.
    /// </summary>
    public void NewGame()
    {
        // Play sound effect
        AudioManager.instance.PlayClickSound();

        // Reset game attributes and metrics
        ScoreManager.instance.score = 0;
        currentWave = 1;
        Performance.shotsFired = 0;
        Performance.damageDealt = 0;
        Performance.shipsDestroyed = 0;

        // Restart the game scene
        SceneManager.LoadScene("Game");
    }
}
