package server

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

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

func GetSoundCheckSong() string {
	Reset()

	files, err := ioutil.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)
		db.AddGamePlayed(lastFetched.GameId)
		songQue = append(songQue, lastFetched)
		lastFetched = models.SongData{}
	}
}

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

	song := getSongFromList(games)

	lastFetched = song
	return song.Path
}

func GetRandomSongLowChance() string {
	gameList := db.FindAllGames()

	var listOfGames []models.GameData

	var averagePlayed = getAveragePlayed(gameList)

	for _, data := range gameList {
		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 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.Seed(time.Now().UnixNano())
	rand.Shuffle(len(jsonArray), func(i, j int) { jsonArray[i], jsonArray[j] = jsonArray[j], jsonArray[i] })
	return jsonArray
}

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

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)
		songs := db.FindSongsFromGame(game.Id)
		song = songs[rand.Intn(len(songs))]

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

		err = openFile.Close()
		if err != nil {
			log.Fatal(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))]
}
