package fr.rolandl.mymovies

import fr.rolandl.mymovies.bo.Film
import fr.rolandl.mymovies.bo.Person
import fr.rolandl.mymovies.service.MovieService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

fun main()
{
  runBlocking {
    println("Bienvenu dans le programme My Movie !")

    var userChoice: Int?

    do
    {
      println("\nQue voulez-vous faire ?\n")
      println("0. Quitter le programme")
      println("1. Charger une précédente base de données")
      println("2. Sauvegarder la base de données")
      println("3. Ajouter un film")
      println("4. Ajouter une personne")
      println("5. Rechercher un film par son nom")
      println("6. Afficher les films d'un acteur")
      println("7. Afficher les films d'un réalisateur")
      println("8. Afficher les films d'un genre particulier")

      print("\nSaisissez votre choix : ")

      userChoice = readLine()?.toInt()

      when (userChoice)
      {
        //..
        0 -> println("\nA bientôt !\n")
        1 -> loadDatabase()
        2 -> saveDatabase()
        3 -> addFilm()
        4 -> addPerson()
        5 -> findFilmByName()
        6 -> findFilmsForActor()
        7 -> findFilmsForDirector()
        8 -> findFilmsForGenre()
        else -> println("\nOption choisie inconnue\n")
      }
    }
    while (userChoice != 0)
  }
}

suspend fun findFilmsForGenre()
{
  println("Chargment des données en cours...\n")

  val genresDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getAllGenres()
  }

  val genres = genresDeferred.await()

  println("Liste des genres :")
  genres.forEach { println(it) }

  print("Saisir le nom du genre : ")
  val genre = readLine() ?: ""

  val filmDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getFilmByGenre(Film.Genre.valueOf(genre))
  }

  val films = filmDeferred.await()

  if (films.isEmpty() == false)
  {
    println("Les films suivants ont été trouvés :")
    films.forEach { println(it) }
  }
  else
  {
    print("Aucun film trouvé !")
  }
}

suspend fun findFilmsForDirector()
{
  println("Chargment des données en cours...\n")

  val personsDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getAllPersons()
  }

  val persons = personsDeferred.await()

  println("Liste des personnes :")
  persons.forEach { println("${it.id} - ${it.firstname} ${it.lastname}") }

  print("Saisir l'identifiant du réalisateur : ")
  val directorId = readLine()?.toInt() ?: 0

  val filmDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getFilmByDirectorId(directorId)
  }

  val films = filmDeferred.await()

  if (films.isEmpty() == false)
  {
    println("Les films suivants ont été trouvés :")
    films.forEach { println(it) }
  }
  else
  {
    print("Aucun film trouvé !")
  }
}

suspend fun findFilmsForActor()
{
  println("Chargment des données en cours...\n")

  val personsDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getAllPersons()
  }

  val persons = personsDeferred.await()

  println("Liste des personnes :")
  persons.forEach { println("${it.id} - ${it.firstname} ${it.lastname}") }

  print("Saisir l'identifiant de l'acteur : ")
  val actorId = readLine()?.toInt() ?: 0

  val filmDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getFilmByActorId(actorId)
  }

  val films = filmDeferred.await()

  if (films.isEmpty() == false)
  {
    println("Les films suivants ont été trouvés :")
    films.forEach { println(it) }
  }
  else
  {
    print("Aucun film trouvé !")
  }
}

suspend fun findFilmByName()
{
  print("Saisir le titre du film recherché : ")
  val title = readLine() ?: ""

  println("Chargment des données en cours...\n")

  val deferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getFilmByName(title)
  }

  val film = deferred.await()

  if (film != null)
  {
    println("Le film suivant a été trouvé :")
    println(film)
  }
  else
  {
    print("Aucun film trouvé !")
  }
}

suspend fun addFilm()
{
  println("Chargment des données en cours...\n")

  val personsDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getAllPersons()
  }

  val genresDeferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.getAllGenres()
  }

  val persons = personsDeferred.await()
  val genres = genresDeferred.await()

  print("Saisir le titre du film : ")
  val title = readLine() ?: ""

  print("Saisir la date de réalisation  : ")
  val releaseYear = readLine()?.toInt() ?: 2020

  print("Saisir la durée du film : ")
  val duration = readLine()?.toInt() ?: 0

  println("Liste des personnes :")
  persons.forEach { println("${it.id} - ${it.firstname} ${it.lastname}") }

  print("Saisir l'identifiant du réalisateur : ")
  val directorId = readLine()?.toInt() ?: 0

  var actorsCount: Int

  do
  {
    print("Combien d'acteur voulez-vous ajouter (entre 1 et 4) : ")
    actorsCount = readLine()?.toInt() ?: 0
  }
  while (actorsCount !in 1..4)

  val actorIds = mutableListOf<Int>()
  for (index in 0 until actorsCount)
  {
    print("Saisir l'identifiant de l'acteur n°${index + 1} : ")
    readLine()?.toInt()?.let {
      actorIds.add(it)
    }
  }

  println("Liste des genres :")
  genres.forEach { println(it.name) }

  var genresCount: Int

  do
  {
    print("Combien de genres voulez-vous ajouter (entre 1 et 2) : ")
    genresCount = readLine()?.toInt() ?: 0
  }
  while (genresCount !in 1..2)

  val selectedGenres = mutableListOf<Film.Genre>()
  for (index in 0 until genresCount)
  {
    print("Saisir le genre n°${index + 1} : ")
    readLine()?.let {
      selectedGenres.add(Film.Genre.valueOf(it))
    }
  }

  GlobalScope.launch(Dispatchers.IO) {
    val film = Film(title, releaseYear, directorId, actorIds, duration, selectedGenres)

    MovieService.addFilm(film)
  }
}

fun addPerson()
{
  print("Saisir le nom de la personne : ")
  val lastName = readLine() ?: ""

  print("Saisir le prénom de la personne : ")
  val firstname = readLine() ?: ""

  print("Saisir la nationalité de la personne : ")
  val nationality = readLine() ?: ""

  print("Saisir la date de naissance de la personne : ")
  val birthDate = readLine()?.split("/")?.map { it.toInt() } ?: listOf(1, 1, 1970)

  GlobalScope.launch(Dispatchers.IO) {
    val person = Person(firstname, lastName, Person.BirthDate(birthDate[0], birthDate[1], birthDate[2]), nationality)

    MovieService.addPerson(person)
  }
}

fun saveDatabase()
{
  GlobalScope.launch(Dispatchers.IO) {
    MovieService.saveDatabase()
  }
}

suspend fun loadDatabase()
{
  val deferred = GlobalScope.async(Dispatchers.IO) {
    MovieService.loadDatabase()
  }

  deferred.await()
}
