package server

import (
	"log"
	"math/rand"
	"music-server/pkg/db"
	"music-server/pkg/models"
	"os"
	"strconv"
	"strings"
)

var currentSong = -1
var games []models.GameData
var songQue []models.SongData
var lastFetched models.SongData

func GetSoundCheckSong() string {
	files, err := os.ReadDir("songs")
	if err != nil {
		log.Fatal(err)
	}
	fileInfo := files[rand.Intn(len(files))]
	return "songs/" + fileInfo.Name()
}

func Reset() {
	songQue = nil
	currentSong = -1
	games = db.FindAllGames()
}

func AddLatestToQue() {
	if lastFetched.Path != "" {
		currentSong = len(songQue)
		songQue = append(songQue, lastFetched)
		lastFetched = models.SongData{}
	}
}

func AddLatestPlayed() {
	if len(songQue) == 0 {
		return
	}
	var currentSongData = songQue[currentSong]

	db.AddGamePlayed(currentSongData.GameId)
	db.AddSongPlayed(currentSongData.GameId, currentSongData.SongName)
}

func SetPlayed(songNumber int) {
	if len(songQue) == 0 || songNumber >= len(songQue) {
		return
	}
	var songData = songQue[songNumber]
	db.AddGamePlayed(songData.GameId)
	db.AddSongPlayed(songData.GameId, songData.SongName)
}

func GetRandomSong() string {
	if len(games) == 0 {
		games = db.FindAllGames()
	}
	if len(games) == 0 {
		return ""
	}

	song := getSongFromList(games)
	lastFetched = song
	return song.Path
}

func GetRandomSongLowChance() string {
	if len(games) == 0 {
		games = db.FindAllGames()
	}

	var listOfGames []models.GameData

	var averagePlayed = getAveragePlayed(games)

	for _, data := range games {
		var timesToAdd = averagePlayed - data.TimesPlayed
		if timesToAdd <= 0 {
			listOfGames = append(listOfGames, data)
		} else {
			for i := 0; i < timesToAdd; i++ {
				listOfGames = append(listOfGames, data)
			}
		}
	}
	song := getSongFromList(listOfGames)

	lastFetched = song
	return song.Path

}

func GetRandomSongClassic() string {
	if games == nil || len(games) == 0 {
		games = db.FindAllGames()
	}

	var listOfAllSongs []models.SongData
	for _, game := range games {
		listOfAllSongs = append(listOfAllSongs, db.FindSongsFromGame(game.Id)...)
	}

	songFound := false
	var song models.SongData
	for !songFound {
		song = listOfAllSongs[rand.Intn(len(listOfAllSongs))]
		gameData, err := db.GetGameById(song.GameId)

		if err != nil {
			db.RemoveBrokenSong(song)
			log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
			continue
		}

		//Check if file exists and open
		openFile, err := os.Open(song.Path)
		if err != nil || gameData.Path+song.FileName != song.Path {
			//File not found
			db.RemoveBrokenSong(song)
			log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + gameData.GameName + "' FileName: " + song.FileName)
		} else {
			songFound = true
		}
		err = openFile.Close()
		if err != nil {
			log.Println(err)
		}
	}
	lastFetched = song
	return song.Path
}

func GetSongInfo() models.SongInfo {
	if songQue == nil {
		return models.SongInfo{}
	}
	var currentSongData = songQue[currentSong]

	currentGameData := getCurrentGame(currentSongData)

	return models.SongInfo{
		Game:             currentGameData.GameName,
		GamePlayed:       currentGameData.TimesPlayed,
		Song:             currentSongData.SongName,
		SongPlayed:       currentSongData.TimesPlayed,
		CurrentlyPlaying: true,
		SongNo:           currentSong,
	}
}

func GetPlayedSongs() []models.SongInfo {
	var songList []models.SongInfo

	for i, song := range songQue {
		gameData := getCurrentGame(song)
		songList = append(songList, models.SongInfo{
			Game:             gameData.GameName,
			GamePlayed:       gameData.TimesPlayed,
			Song:             song.SongName,
			SongPlayed:       song.TimesPlayed,
			CurrentlyPlaying: i == currentSong,
			SongNo:           i,
		})
	}
	return songList
}

func GetSong(song string) string {
	currentSong, _ = strconv.Atoi(song)
	if currentSong >= len(songQue) {
		currentSong = len(songQue) - 1
	} else if currentSong < 0 {
		currentSong = 0
	}
	var songData = songQue[currentSong]
	return songData.Path
}

func GetAllGames() []string {
	if games == nil || len(games) == 0 {
		games = db.FindAllGames()
	}

	var jsonArray []string
	for _, game := range games {
		jsonArray = append(jsonArray, game.GameName)
	}
	return jsonArray
}

func GetAllGamesRandom() []string {
	if games == nil || len(games) == 0 {
		games = db.FindAllGames()
	}

	var jsonArray []string
	for _, game := range games {
		jsonArray = append(jsonArray, game.GameName)
	}
	rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
	return jsonArray
}

func GetNextSong() string {
	if songQue == nil {
		return ""
	}
	if currentSong == len(songQue)-1 || currentSong == -1 {
		var songData = songQue[currentSong]
		return songData.Path
	} else {
		currentSong = currentSong + 1
		var songData = songQue[currentSong]
		return songData.Path
	}
}

func GetPreviousSong() string {
	if songQue == nil {
		return ""
	}
	if currentSong == -1 || currentSong == 0 {
		var songData = songQue[0]
		return songData.Path
	} else {
		currentSong = currentSong - 1
		var songData = songQue[currentSong]
		return songData.Path
	}
}

func getSongFromList(games []models.GameData) models.SongData {
	songFound := false
	var song models.SongData
	for !songFound {
		game := getRandomGame(games)
		//log.Println("game = ", game)
		songs := db.FindSongsFromGame(game.Id)
		//log.Println("songs = ", songs)
		if len(songs) == 0 {
			continue
		}
		song = songs[rand.Intn(len(songs))]
		log.Println("song = ", song)

		//Check if file exists and open
		openFile, err := os.Open(song.Path)
		//log.Println("game.Path+song.FileName: ", game.Path+song.FileName)
		//log.Println("song.Path: ", song.Path)
		//log.Println("game.Path+song.FileName != song.Path: ", game.Path+song.FileName != song.Path)
		if err != nil || game.Path+song.FileName != song.Path || strings.HasSuffix(song.FileName, ".wav") {
			//File not found
			db.RemoveBrokenSong(song)
			log.Println("Song not found, song '" + song.SongName + "' deleted from game '" + game.GameName + "' FileName: " + song.FileName)
		} else {
			songFound = true
		}

		err = openFile.Close()
		if err != nil {
			log.Println(err)
		}
	}
	return song
}

func getCurrentGame(currentSongData models.SongData) models.GameData {
	for _, game := range games {
		if game.Id == currentSongData.GameId {
			return game
		}
	}
	return models.GameData{}
}

func getAveragePlayed(gameList []models.GameData) int {
	var sum int
	for _, data := range gameList {
		sum += data.TimesPlayed
	}
	return sum / len(gameList)
}

func getRandomGame(listOfGames []models.GameData) models.GameData {
	return listOfGames[rand.Intn(len(listOfGames))]
}
