using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using TMPro;
using UnityEngine;

public enum EPoorAssEnemyEncounterTypes
{
    one_swarmer = 0,
    redstar_group_small,
    redstar_and_swarmers,
    redstar_group_large,
    bone_sat_small,
    bone_sat_and_redstar,
    redstar_and_heart,
    bone_sat_and_heart,
    zeppelin,
    zeppelin_and_more,
}

public class LDWorldSpawnManager : MonoBehaviour
{
    public GameObject Prefab_AsteroidObject;
    public GameObject Prefab_AsteroidSpawner;

    [Header("Baddies")] 
    public GameObject Prefab_Enemy_Redstar;
    public GameObject Prefab_Enemy_Swarmer;
    public GameObject Prefab_Enemy_Metalheart;
    public GameObject Prefab_Enemy_BoneSat;
    public GameObject Prefab_Enemy_Zeppelin;


    private List<Vector2> vEnemySpawnLocations;

    private List<List<EPoorAssEnemyEncounterTypes>> enemySpawnWaves;

    private GameManager theGame;

    private float fTotalGameTime;
    private float fTimeUntilNextSpawn;
    private int iCurrentWave;

    void Start ()
    {
        theGame = GameManager.GetGame();
        HackTogetherEnemySpawnWaves();

    }

    public void PrepareForNewGame()
    {
        iCurrentWave = 1;
        fTotalGameTime = 0f;
        PlaceEnemySpawnLocations();

    }

	void Update ()
	{
	    if (theGame.GetGameState() == EGameState.gameplay)
	    {
	        fTotalGameTime += Time.deltaTime;
	        if (fTotalGameTime < 20f)
	        {
	            iCurrentWave = 1;
	        }
            else if (fTotalGameTime < 60f)
	        {
	            iCurrentWave = 2;
	        }
	        else
	        {
	            iCurrentWave = (int)(fTotalGameTime / 30f);
	        }
	
	        fTimeUntilNextSpawn -= Time.deltaTime;
	        if (fTimeUntilNextSpawn < 0f)
	        {
	            Vector2 vEnemySpawn = PickEnemySpawnLocation();
	            if (vEnemySpawn != Vector2.zero)
	            {
	                fTimeUntilNextSpawn = (10.0f - (float)iCurrentWave * 0.5f);

	                if (fTimeUntilNextSpawn < 5.0f)
	                {
	                    fTotalGameTime = 5.0f;
	                }

	                int iListToUse = Mathf.Min(iCurrentWave - 1, enemySpawnWaves.Count - 1);
	                SpawnEncounter(enemySpawnWaves[iListToUse], vEnemySpawn);
                    Debug.Log("I spawned a thing at " + vEnemySpawn );
	            }
	        }
        }
	}

    void SpawnEncounter(List<EPoorAssEnemyEncounterTypes> encounterList , Vector2 vLocation)
    {
        EPoorAssEnemyEncounterTypes enc = encounterList[Random.Range(0, encounterList.Count)];
        switch (enc)
        {
            case EPoorAssEnemyEncounterTypes.one_swarmer:
                SpawnOneSwarmer(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.redstar_group_small:
                SpawnRedstarGroupSmall(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.redstar_and_swarmers:
                SpawnRedstarAndSwarmer(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.redstar_group_large:
                SpawnRedstarGroupLarge(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.bone_sat_small:
                SpawnBoneSatGroupSmall(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.bone_sat_and_redstar:
                SpawnBoneSatsAndRedstars(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.redstar_and_heart:
                SpawnHeartAndRedstars(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.bone_sat_and_heart:
                SpawnBoneSatAndHearts(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.zeppelin:
                SpawnZeppelin(vLocation);
                break;
            case EPoorAssEnemyEncounterTypes.zeppelin_and_more:
                SpawnZeppelinAndMore(vLocation);
                break;

        }
    }

    public void PlaceStartingAsteroids(Vector2 vStartPosition)
    {
        theGame = GameManager.GetGame();

        //place some asteroids near the start
        for (int t = 0; t < 15; t++)
        {
            Vector2 vOffset = vStartPosition + Random.insideUnitCircle.normalized * Random.Range(14f, 30f);
            theGame.SpawnActorPrefab(vOffset, Prefab_AsteroidObject);
        }

        //and then spawners too 
        for (int t = 0; t < 15; t++)
        {
            Vector2 vOffset = vStartPosition + Random.insideUnitCircle.normalized * Random.Range(22f, 40f);
            theGame.SpawnActorPrefab(vOffset, Prefab_AsteroidSpawner);
        }
    }

    void PlaceEnemySpawnLocations()
    {
        vEnemySpawnLocations = new List<Vector2>();
        int iNumSpawnLocations = 100;

        for (int t = 0; t < iNumSpawnLocations; t++)
        {
            int iWeightedXRoll = GetStretchedBellCurveValue(40, 7, 2);
            int iWeightedYRoll = GetStretchedBellCurveValue(40, 7, 2);

            Vector2 vPos = new Vector2(200 - iWeightedXRoll, 200- iWeightedYRoll);
            if (vPos.x < 20)
            {
                vPos.x = 20;
            }

            if (vPos.y < 20)
            {
                vPos.y = 20;
            }
            vEnemySpawnLocations.Add(vPos);

            theGame.SpawnActorPrefab(vPos, Prefab_AsteroidSpawner);
        }

    }

    Vector2 PickEnemySpawnLocation()
    {
        // no one can see

        // isn't near a landmark

        int iTries = 100;
        while (iTries > 0)
        {
            iTries--;

            Vector2 vCheckPos = vEnemySpawnLocations[Random.Range(0, vEnemySpawnLocations.Count)];

            if (theGame.theAIManager.IsPositionNearLandmark(vCheckPos, 15))
            {
                continue;
            }

            if (theGame.theAIManager.GetClosestTarget(EFaction.enemy, 20, vCheckPos, false)  != null)
            {
                continue;
            }

            return vCheckPos;
        }

        return Vector2.zero;
    }

    int GetStretchedBellCurveValue(int iDieSize, int iNumRolls, int iStretchyMultiplier)
    {
        int iMax = iDieSize * iNumRolls;
        if (iMax < 4)
        {
            return 0;
        }

        int iResult = -1;
        while (iResult < 0)
        {
            int iTotal = 0;

            //roll all dice
            for (int t = 0; t < iNumRolls; t++)
            {
                iTotal += Random.Range(1, iDieSize + 1);
            }

            //number nice and bellcurvy
            iTotal -= (iMax / 2);

            iResult = iTotal * iStretchyMultiplier;

        }
        return iResult;
    }



    public void HackTogetherEnemySpawnWaves()
    {
        enemySpawnWaves = new List<List<EPoorAssEnemyEncounterTypes>>();

        List<EPoorAssEnemyEncounterTypes> waveList;
        //rank 1 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.one_swarmer);
        waveList.Add(EPoorAssEnemyEncounterTypes.one_swarmer);

        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_group_small);

        enemySpawnWaves.Add(waveList);

        //rank 2 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.one_swarmer);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_group_small);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_swarmers);

        enemySpawnWaves.Add(waveList);

        //rank 3 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_swarmers);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_swarmers);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_group_large);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_small);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_redstar);

        enemySpawnWaves.Add(waveList);

        //rank 4 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_swarmers);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_group_large);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_redstar);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_heart);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_heart);


        enemySpawnWaves.Add(waveList);

        //rank 5 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_swarmers);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_group_large);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_redstar);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_heart);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_heart);


        enemySpawnWaves.Add(waveList);

        //rank 6 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();

        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_redstar);
        waveList.Add(EPoorAssEnemyEncounterTypes.bone_sat_and_heart);
        waveList.Add(EPoorAssEnemyEncounterTypes.redstar_and_heart);
        waveList.Add(EPoorAssEnemyEncounterTypes.zeppelin_and_more);

        enemySpawnWaves.Add(waveList);


        //rank 7 ================================================================
        waveList = new List<EPoorAssEnemyEncounterTypes>();
        waveList.Add(EPoorAssEnemyEncounterTypes.zeppelin_and_more);
        enemySpawnWaves.Add(waveList);
    }

    /*
        one_swarmer = 0,
        redstar_group_small,
        redstar_and_swarmers,
        redstar_group_large,
        bone_sat_small,
        bone_sat_and_redstar,
        redstar_and_heart,
        bone_sat_and_heart,
        zeppelin,
        zeppelin_and_more,
    */

    void SpawnOneSwarmer(Vector2 vLocation )
    {
        //just put a swarmer at the location, and then throw out two redstars
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Swarmer);
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Redstar);
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Redstar);


    }
    void SpawnRedstarGroupSmall(Vector2 vLocation)
    {
        //1d3 + 1d2
        int iNumRedtars = Random.Range(1, 4) + Random.Range(1, 3);
        for (int t = 0; t < iNumRedtars; t++)
        {
            theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Redstar);
        }
    }

    void SpawnRedstarGroupLarge(Vector2 vLocation)
    {
        //4d3
        int iNumRedtars = Random.Range(1, 4) + Random.Range(1, 4) + Random.Range(1, 4) + Random.Range(1, 4);
        for (int t = 0; t < iNumRedtars; t++)
        {
            theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Redstar);
        }
    }

    void SpawnRedstarAndSwarmer(Vector2 vLocation)
    {
        SpawnRedstarGroupSmall(vLocation);
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Swarmer);
    }

    void SpawnBoneSatGroupSmall(Vector2 vLocation)
    {
        int iNumEnemies = Random.Range(1, 4);
        for (int t = 0; t < iNumEnemies; t++)
        {
            theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_BoneSat);
        }
    }
    void SpawnBoneSatsAndRedstars(Vector2 vLocation)
    {
        SpawnBoneSatGroupSmall(vLocation);
        SpawnRedstarGroupSmall(vLocation);
    }
    void SpawnHeartAndRedstars(Vector2 vLocation)
    {
        int iNumHearts = Random.Range(1, 3);
        for (int t = 0; t < iNumHearts; t++)
        {
            theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Metalheart);
        }
        SpawnRedstarGroupLarge(vLocation);
    }
    void SpawnBoneSatAndHearts(Vector2 vLocation)
    {
        int iNumHearts = Random.Range(1, 3);
        for (int t = 0; t < iNumHearts; t++)
        {
            theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Metalheart);
        }
        SpawnBoneSatGroupSmall(vLocation);
    }
    void SpawnZeppelin(Vector2 vLocation)
    {
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Zeppelin);
    }
    void SpawnZeppelinAndMore(Vector2 vLocation)
    {
        theGame.SpawnActorPrefab(vLocation, Prefab_Enemy_Zeppelin);
        SpawnBoneSatAndHearts(vLocation);
        SpawnBoneSatAndHearts(vLocation);
        SpawnRedstarGroupLarge(vLocation);

    }
}
