using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UIElements;
using System.Linq;

using UITypes;
using BangerTypes;
using Unity.VisualScripting;

public class Game : MonoBehaviour
{
	const float DELAY = 0.005f; // 200 TPS

	public AudioManager manager;

	private MainMenu menu;
	private BassEffect effect;

	string totalDuration;
	bool repeatRoutine = true;

	Song song = null;

	List<Note> allNotes = new();

	List<Note> activeNotes = new();

	public int Score { get; set; } = 0;

	void Awake()
	{
		menu = GetComponent<MainMenu>();

		effect = new(manager.source);
	}

	public void GameUpdate()
	{
		float[] specData = effect.UpdateSpectrumData();
		float bassStrength = effect.GetBassStrength();

		menu.GameElem.UpdateVisualizers(specData, bassStrength);

		UpdateTimestamp();
		GetNotes();
	}

	public void GetNotes()
	{
		float timestamp = manager.source.time;

		List<Note> newNotes = allNotes.Where(note => note.t >= timestamp && timestamp + 1f <= note.t).ToList();
		
		foreach (Note note in newNotes)
		{
			allNotes.Remove(note);
		}

		menu.GameElem.UpdateNotes(newNotes);
		menu.GameElem.CheckNoteLifetime(timestamp);
		menu.GameElem.UpdateMargin(timestamp);
	}

	IEnumerator GameLoop()
	{
		while (repeatRoutine)
		{
			GameUpdate();
			yield return new WaitForSeconds(DELAY);
		}
	}

	public void LoadSong(SongEntry song)
	{
		this.song = song.Song;
		allNotes = this.song.Notes.ToList();

		totalDuration = song.Song.Duration;

		manager.source.clip = song.Song.Clip;

		menu.GameElem.SetColumnColor(song.Song.AverageColor);
	}

	void UpdateTimestamp()
	{
		int totalSeconds = (int)manager.source.time;
		int h = totalSeconds / 3600;
		int m = totalSeconds % 3600 / 60;
		int s = totalSeconds % 60;

		string result = $"{h:D2}:{m:D2}:{s:D2} / {totalDuration}";
		menu.GameElem.UpdateSongTime(result);
	}

	public void EscapeClicked()
	{
		repeatRoutine = false;
		manager.Stop();
		menu.Escape();
	}

	public void Play()
	{
		manager.Play();
		repeatRoutine = true;
		StartCoroutine(GameLoop());
	}
}
