//
//  GameEngine.swift
//  Pendu
//
//  Created by Sofiane Lasri-Trienpont on 09/05/2023.
//

import UIKit
import CoreData

class GameEngine: NSObject {

    private var listThemeAnimalsEasy : [String] = ["Chien", "Chat", "Lion", "Girafe", "Éléphant", "Serpent", "Oiseau", "Tigre", "Papillon", "Singe"];
    private var listThemeSportsEasy : [String] = ["Football", "Basket-ball", "Tennis", "Natation", "Rugby", "Golf", "Volley-ball", "Baseball", "Athlétisme", "Boxe"];
    private var listThemeFoodEasy : [String] = ["Pomme", "Banane", "Carotte", "Poisson", "Riz", "Fromage", "Pain", "Chocolat", "Fraise", "Poulet"];
    private var listThemeCitiesEasy : [String] = ["Paris", "Londres", "New York", "Rome", "Tokyo", "Sydney", "Barcelone", "Berlin", "Istanbul", "Mumbai"];
    private var listThemeColorsEasy : [String] = ["Rouge", "Bleu", "Vert", "Jaune", "Rose", "Violet", "Orange", "Gris", "Marron", "Noir"];

    private var listThemeAnimalsHard : [String] = ["Chimpanzé", "Lynx", "Hippopotame", "Pélican", "Kangourou", "Anaconda", "Chimère", "Panda roux", "Calmar géant", "Ouistiti"];
    private var listThemeSportsHard : [String] = ["Escrime", "Squash", "Haltérophilie", "Badminton", "Ski de fond", "Pentathlon moderne", "Canoë-kayak", "Aviron", "Patinage artistique", "Triathlon"];
    private var listThemeFoodHard : [String] = ["Artichaut", "Quinoa", "Courge", "Wasabi", "Chou-fleur", "Sarrasin", "Salsifis", "Morue", "Canneberge", "Pistache"];
    private var listThemeCitiesHard : [String] = ["Copenhague", "Budapest", "Dubrovnik", "Séoul", "Marrakech", "Reykjavik", "La Nouvelle-Orléans", "Bratislava", "Wellington", "Accra"];
    private var listThemeColorsHard : [String] = ["Écarlate", "Azur", "Émeraude", "Safran", "Pourpre", "Indigo", "Sienne", "Cyan", "Vermillon", "Lavande"];
    
    private var wordToGuess : String = "";
    private var attemptsRemaining : Int = 0;
    private var guessedLetters : [Character] = [];
    private var lastGuessedLetterTime : Date? = nil;
    private var theme : String = "";
    private var difficulty : String = "";
    private var playerName : String = "";
    private var score : Int = 0;
    private var combo : Int = 0;
    private var remainingLives : Int = 8;
    
    private var managedObjectContext: NSManagedObjectContext?;
 
    override init() {
        //
    }
    
    func WordToGuess(theme: String, difficulty: String) -> String{
        var word = ""
        self.theme = theme;
        self.difficulty = difficulty;
        if theme == "Animals"{
            if difficulty == "Easy"{
                let randomInt = Int.random(in: 0..<listThemeAnimalsEasy.count)
                word = listThemeAnimalsEasy[randomInt]
            } else {
                let randomInt = Int.random(in: 0..<listThemeAnimalsHard.count)
                word = listThemeAnimalsHard[randomInt]
            }
        } else if theme == "Sports"{
            if difficulty == "Easy"{
                let randomInt = Int.random(in: 0..<listThemeSportsEasy.count)
                word = listThemeAnimalsEasy[randomInt]
            } else {
                let randomInt = Int.random(in: 0..<listThemeSportsHard.count)
                word = listThemeSportsHard[randomInt]
            }
        } else if theme == "Food"{
            if difficulty == "Easy"{
                let randomInt = Int.random(in: 0..<listThemeFoodEasy.count)
                word = listThemeFoodEasy[randomInt]
            } else {
                let randomInt = Int.random(in: 0..<listThemeFoodHard.count)
                word = listThemeFoodHard[randomInt]
            }
        } else if theme == "Cities"{
            if difficulty == "Easy"{
                let randomInt = Int.random(in: 0..<listThemeCitiesEasy.count)
                word = listThemeCitiesEasy[randomInt]
            } else {
                let randomInt = Int.random(in: 0..<listThemeCitiesHard.count)
                word = listThemeCitiesHard[randomInt]
            }
        } else if theme == "Colors"{
            if difficulty == "Easy"{
                let randomInt = Int.random(in: 0..<listThemeColorsEasy.count)
                word = listThemeColorsEasy[randomInt]
            } else {
                let randomInt = Int.random(in: 0..<listThemeColorsHard.count)
                word = listThemeColorsHard[randomInt]
            }
        }
        return word
    }
    
    public func guessLetter(letter: Character) -> Bool {
        if(isGameOver()){
            return false;
        }
        
        guessedLetters.append(letter);
        
        if wordToGuess.contains(letter) {
            combo += 1;
            let dateNow = Date();
            
            let maxElapsedTimeInSecondsForBonus = 100;
            var elapsedTimeInSeconds = maxElapsedTimeInSecondsForBonus; // Initialisation au temps max
            let baseGuessedLetterBonusPoint = 100;
            let baseBonusPoint = 100;
            let comboBonusPoints = 50;
            var timeBonusMultiplier = 1;
            
            if(lastGuessedLetterTime != nil) {
                elapsedTimeInSeconds = Int(dateNow.timeIntervalSince(lastGuessedLetterTime!));
            }
            
            switch difficulty {
            case "Easy":
                timeBonusMultiplier = 1;
            case "Normal":
                timeBonusMultiplier = 2;
            case "Hard":
                timeBonusMultiplier = 3;
            default:
                timeBonusMultiplier = 1;
            }
            
            if(elapsedTimeInSeconds > maxElapsedTimeInSecondsForBonus) {
                score += baseGuessedLetterBonusPoint;
            } else if(elapsedTimeInSeconds < 10) {
                score += baseGuessedLetterBonusPoint + baseBonusPoint * timeBonusMultiplier;
            } else {
                score += baseGuessedLetterBonusPoint + (baseBonusPoint * (elapsedTimeInSeconds / maxElapsedTimeInSecondsForBonus));
            }
            if (combo > 1) {
                score += (combo - 1) * comboBonusPoints;
            }
            
            lastGuessedLetterTime = Date();
            return true;
        }
        
        remainingLives -= 1;
        combo = 0;
        lastGuessedLetterTime = nil;
        return false;
    }
    
    public func isGameOver() -> Bool {
        if(remainingLives > 0) {
            return false;
        }
        return true;
    }
    
    public func isLetterGuessed(letter: Character) -> Bool {
        if(guessedLetters.contains(letter)) {
            return true;
        }
        return false;
    }
    
    public func getScore() -> Int {
        return self.score;
    }
    
    public func saveScore() -> Void {
        // Enregistrement du score dans la base Core Data
        
        // Création du gestionnaire d'objets persistants
        let context: NSManagedObjectContext = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext;
        
        // Création de l'instance de l'entité CoreData
        let entity = NSEntityDescription.entity(forEntityName: "Score", in: context)!;
        let object = NSManagedObject(entity: entity, insertInto: context);
        object.setValue(theme, forKeyPath: "categoryName");
        object.setValue(difficulty, forKeyPath: "difficulty");
        object.setValue(playerName, forKeyPath: "playerName");
        object.setValue(score, forKeyPath: "score");
        
        // On enregistre
        do {
            try context.save();
        } catch let error as NSError {
            print("Erreur lors de l'enregistrement des données : \(error), \(error.userInfo)");
        }
    }
    
    static func getOnlineScoreboard() -> Void {
        // Récupération du classement depuis le serveur

        // URL de l'API
        let url = URL(string: "https://miscs.sl-projects.com/IUT-ORSAY/LP-PRISM/TP-iOS/")!

        // Création de la tâche de session URLSessionDataTask pour récupérer les données
        let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
            // Vérification des erreurs et de la disponibilité des données
            guard let data = data, error == nil else {
                print("Erreur lors de la récupération des données : \(error?.localizedDescription ?? "Erreur inconnue")")
                return
            }
            
            // Récupération du contexte Core Data
            guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
                print("Impossible d'obtenir l'AppDelegate")
                return
            }
            let managedContext = appDelegate.persistentContainer.viewContext
            
            do {
                // Décodage du JSON en une liste de dictionnaires
                guard let jsonArray = try JSONSerialization.jsonObject(with: data, options: []) as? [[String: Any]] else {
                    print("Le JSON n'est pas au format attendu.")
                    return
                }
                
                // Utilisation des données JSON
                for jsonScore in jsonArray {
                    // Création d'une instance NSManagedObject pour le score
                    let scoreObject = Score(context: managedContext)
                    
                    // Association des valeurs du JSON aux attributs du modèle Core Data
                    scoreObject.categoryName = jsonScore["categoryName"] as? String ?? ""
                    scoreObject.difficulty = jsonScore["difficulty"] as? String ?? ""
                    scoreObject.playerName = jsonScore["playerName"] as? String ?? ""
                    
                    if let scoreValue = jsonScore["score"] as? Int {
                        scoreObject.score = Int16(scoreValue)
                    } else if let scoreValueString = jsonScore["score"] as? String,
                              let scoreValue = Int(scoreValueString) {
                        scoreObject.score = Int16(scoreValue)
                    } else {
                        scoreObject.score = 0 // Valeur par défaut si le score ne peut pas être extrait du JSON
                    }
                }
                
                // Sauvegarde du contexte Core Data
                do {
                    try managedContext.save()
                } catch {
                    print("Erreur lors de la sauvegarde du contexte Core Data : \(error.localizedDescription)")
                }
                
                // Récupération des scores enregistrés dans une liste
                let fetchRequest = NSFetchRequest<Score>(entityName: "Score")
                let fetchedScores = try managedContext.fetch(fetchRequest)
                
                // Utilisation de la liste de scores
                for fetchedScore in fetchedScores {
                    print("Category: \(fetchedScore.categoryName)")
                    print("Difficulty: \(fetchedScore.difficulty)")
                    print("Player Name: \(fetchedScore.playerName)")
                    print("Score: \(fetchedScore.score)")
                    print("------------------------")
                }
            } catch {
                print("Erreur lors du décodage JSON : \(error.localizedDescription)")
            }
        }

        // Lancement de la tâche
        task.resume()

    }
}