How to make infinite enemies spawning wave system?

How to make a wave system, if I need to spawn different enemies (enemy1, enemy2, enemy3…) in multiple combinations, also sometimes with pauses. How should I make an algorithm for waves? By the way, I require infinite spawning system.
It should look like:
wave 1: spawn 10 X enemy1
wave 2: spawn 20 X enemy1
wave 3: spawn 20 X enemy1, spawn 10 X enemy2
wave 4: spawn 20 X enemy1, Wait 5 seconds, spawn 20 X enemy2
wave 5: spawn 30 X enemy2
wave 6: spawn 30 X enemy1, Wait 5 seconds, spawn 10 X enemy3

With greater wave number - greater amount of enemies and they should be spawned in various combinations, but later in some waves enemies should be spawned of the same type, abilities.

I really didnt want to code the entire thing but ended up getting carried away. This is the jist of it:

private int wave = 0;
private int numOfTotalWaves = 10;
private int numOfEnemyTypes = 3;
private int[,] waveSpawnCount = new int[numOfTotalWaves, numOfEnemyTypes];
private int aliveEnemies = 0; // Will count how many enemies are currently alive, MAKE SURE TO HAVE THIS DECREASE WHEN ONE DIES

void Start()
{
	//Set Wave 0 to 0 spawns because we dont want anything to spawn in wave 0.
	waveSpawnCount[0, 0] = 0;
	waveSpawnCount[0, 1] = 0;
	waveSpawnCount[0, 2] = 0;
	
	waveSpawnCount[1, 0] = 10;	//Store that we want 10 of Enemy 0 to spawn in Wave 1
	waveSpawnCount[1, 1] = 0;
	waveSpawnCount[1, 2] = 0;
	
	/*
	...
	And So On
	...
	*/
}

void Update()
{
	if(aliveEnemies <= 0)
	{
		if(wave <= numOfTotalWaves)
		{
			wave++;
			SpawnWave();
		}
	}
}

private void SpawnWave()
{
    for(int enemyType = 0; enemyType != numOfEnemyTypes; enemyType++) // For every enemy Type
	{
      for(int i = 0; i < waveSpawnCount[wave, enemyType]; i++) // and for every number of units to spawn for that enemy type
	  {
	      SpawnEnemy(enemyType); // spawn that enemy type
		  aliveEnemies++; // Add one to our alive enemies counter
	  }
	}
}

private void SpawnEnemy()
{
	switch(enemyType)
	{
		case 0:
		// Do whatever you do to load enemy 0
		break;
		case 1:
		// Do whatever you do to load enemy 1
		break;
		case 2:
		// Do whatever you do to load enemy 2
		break;
	}
}

As for the wait 5 seconds and spawn more stuff thing. You have two options for expanding on the code that I’ve provided that I can think of. Either 1. Just include these things in the regular waves, this will get messy and isnt recommended but if you’re just throwing something together quickly it’ll probably be a easier/quicker solution. OR 2. Have a 2nd 2D Array (the thing where its int[,] that stores the values you have for “extra” waves - basically just duplicate everything there and rename the new ones to extraWaveSpawnCount or something like that and store the numbers you want in there and do the same thing as I do with spawning the regular wave except after a delay. You can save the delay in another array as well. ie private float extraWaveDelay = new float[numOfTotalWaves] then extraWaveDelay[0] = 0.0; extraWaveDelay[1] = 5.0f and have the current wave delay decrease by deltaTime by doing extraWaveDelay[wave] -= Time.deltaTime in Update and then if(extraWaveDelay[wave] <= 0) … SpawnExtraWave(); etc.

Hope this helped.