package server

import (
	"fmt"
	"io/fs"
	"io/ioutil"
	"log"
	"music-server/pkg/db"
	"music-server/pkg/models"
	"os"
	"sort"
	"strconv"
	"strings"
)

func SyncGames() {
	host := os.Getenv("DB_HOST")
	var dir string
	if host != "" {
		dir = "/sorted/"
	} else {
		dir = "/Users/sebastian/Resilio Sync/Sorterat_test/"
	}
	fmt.Printf("dir: %s\n", dir)
	foldersToSkip := []string{".sync"}
	fmt.Println(foldersToSkip)
	db.SetGameDeletionDate()
	checkBrokenSongs()

	files, err := ioutil.ReadDir(dir)
	if err != nil {
		log.Fatal(err)
	}

	for _, file := range files {
		if file.IsDir() && !contains(foldersToSkip, file.Name()) {
			fmt.Println(file.Name())
			path := dir + file.Name() + "/"
			fmt.Println(path)

			innerFiles, err := ioutil.ReadDir(path)
			if err != nil {
				log.Println(err)
			}
			id := -1
			for _, song := range innerFiles {
				id = getIdFromFile(song)
				if id != -1 {
					break
				}
			}
			if id == -1 {
				addNewGame(file.Name(), path)
			} else {
				checkIfChanged(id, file.Name(), path)
				checkSongs(path, id)
			}
		}
	}
}

func ResetDB() {
	db.ClearSongs(-1)
	db.ClearGames()
}

func getIdFromFile(file os.FileInfo) int {
	name := file.Name()
	if !file.IsDir() && strings.HasSuffix(name, ".id") {
		name = strings.Replace(name, ".id", "", 1)
		name = strings.Replace(name, ".", "", 1)
		i, _ := strconv.Atoi(name)
		return i
	}
	return -1
}

func checkIfChanged(id int, name string, path string) {
	fmt.Printf("Id from file: %v\n", id)
	nameFromDb := db.GetGameName(id)
	fmt.Printf("Name from file: %v\n", name)
	fmt.Printf("Name from DB: %v\n", nameFromDb)
	if nameFromDb == "" {
		fmt.Println("Not in db")
		db.InsertGameWithExistingId(id, name, path)
		fmt.Println("Added to db")
	} else if name != nameFromDb {
		fmt.Println("Diff name")
		db.UpdateGameName(id, name, path)
	}
	db.RemoveDeletionDate(id)
}

func addNewGame(name string, path string) {
	newId := db.GetIdByGameName(name)
	if newId == -1 {
		newId = db.InsertGame(name, path)
	}

	fmt.Printf("newId = %v", newId)
	fileName := path + "/." + strconv.Itoa(newId) + ".id"
	fmt.Printf("fileName = %v", fileName)

	err := ioutil.WriteFile(fileName, nil, 0644)
	if err != nil {
		panic(err)
	}
	checkSongs(path, newId)
}

func checkSongs(gameDir string, gameId int) {
	songs := make([]models.SongData, 0)
	findSongsFromGame := db.FindSongsFromGame(gameId)

	files, err := ioutil.ReadDir(gameDir)
	if err != nil {
		log.Println(err)
	}
	for _, entry := range files {
		path := gameDir + entry.Name()
		fileName := entry.Name()
		if isSong(entry) {
			songs = append(songs, models.SongData{GameId: gameId, SongName: fileName, Path: path})
		} else if isCoverImage(entry) {
			//TODO: Later add cover art image here in db
		}
	}
	if len(songs) != len(findSongsFromGame) {
		db.ClearSongs(gameId)
		for _, song := range songs {
			db.AddSong(song)
		}
	}
	//TODO: Add number of songs here
}

func checkBrokenSongs() {
	allSongs := db.FetchAllSongs()
	var brokenSongs []models.SongData
	for _, song := range allSongs {
		//Check if file exists and open
		openFile, err := os.Open(song.Path)
		if err != nil {
			//File not found
			brokenSongs = append(brokenSongs, song)
			fmt.Printf("song broken: %v", song.Path)
		} else {
			err = openFile.Close()
			if err != nil {
				log.Println(err)
			}
		}
	}
	db.RemoveBrokenSongs(brokenSongs)
}

func isSong(entry fs.FileInfo) bool {
	return !entry.IsDir() && strings.HasSuffix(entry.Name(), ".mp3") || strings.HasSuffix(entry.Name(), ".wav")
}

func isCoverImage(entry fs.FileInfo) bool {
	return !entry.IsDir() && strings.Contains(entry.Name(), "cover") &&
		(strings.HasSuffix(entry.Name(), ".jpg") || strings.HasSuffix(entry.Name(), ".png"))
}

func contains(s []string, searchTerm string) bool {
	i := sort.SearchStrings(s, searchTerm)
	return i < len(s) && s[i] == searchTerm
}
