//
//  GameVM.swift
//  DouShouQiIOS
//
//  Created by Pierre FERREIRA on 12/06/2024.
//

import Foundation
import DouShouQiModel
import SpriteKit
import SwiftUI
// Gestion de la boucle de jeu par la création d'une tache async<
// On s'abonne aux événements, notament game.addPlayerNotifiedListeneren.
// Les joueurs n'ont besoin que de nom


class GameVM : ObservableObject, Identifiable {
    
    @Published var game: Game?

    @Published var gameScene: GameScene
    @Published var isGameOver: Bool = false
    
    
    
    ///Players (-game -> todelete)
//    let player1 : Player
//    let player2 : Player
//    var pieces : [ Owner : [Animal : SpriteMeeple]]
//    let actualRules : Rules
    
    ///Error
    @Published var hasError : Bool = false
    
    ///Message
    @Published var displayMessage : String = ""
    
    //On donne directement la scene et la game à la vm
    public init(withGame _game : Game?, andScene _gameScene : GameScene) {

        self.game = _game
        self.gameScene = _gameScene

        ///Abonnement aux événements
        self.game?.addGameStartedListener(onGameStart)
        self.game?.addPlayerNotifiedListener(onPlayerNotified)
        self.game?.addMoveChosenCallbacksListener(onMoveChosen)
        self.game?.addInvalidMoveCallbacksListener(onInvalidMove)
        self.game?.addBoardChangedListener(onBoardChanged)
        self.game?.addGameOverListener(onGameOver)
        //self.game?.addGameChangedListener({}) - //? cas persistance
    }
    
    
    func onGameStart(board : Board){
        displayMessage = "     ==>> 🎉 GAME STARTS! 🎉 <<==     "
    }
    
    func onPlayerNotified(board : Board, player : Player) async{
        if player is HumanPlayer {
            displayMessage = "Player \(player.id == .player1 ? "🟡 1" : "🔴 2") - \(player.name), it's your turn!"
        }
        else {
            do{
                _ = try await player.chooseMove(in: board, with: self.game!.rules)
            }
            catch{
                hasError = true
            }
        }
    }
    
    func onMoveChosen(board : Board, move : Move, player : Player){
        ///Récupération du Meeple :
        let movedPiece = board.grid[move.rowOrigin][move.columnOrigin]
        let meeples = gameScene.pieces[move.owner]
        
        let meeple = meeples?.first(where: {
            $0.key == movedPiece.piece?.animal
        })
        meeple?.value.cellPosition = CGPoint(x: move.rowDestination, y: move.columnDestination)

    }
    
    ///Mouvement invalide
    func onInvalidMove(board : Board, move : Move, player : Player, result : Bool){
        if result { ///* invalidité terminante
            return
        }
        displayMessage = "⚠️⚠️⚠️⚠️ Invalid Move detected: \(move) by \(player.name) (\(player.id))"
    }
    
    func onBoardChanged(board : Board){
        /// Bruit d'un placement de pion ?
    }
    
    func onGameOver(board : Board, result : Result, winner : Player?){
        displayMessage = "Game Over!!!"
        isGameOver = true ///Gestion par l'appelant
    }
    
    
    func readInt(withMessage message: String) -> Int {
        var temp: Int?
        while temp == nil {
            print(message)
            let result = readLine()
            temp = Int(result ?? "")
        }
        return temp!
    }
    
    func readMove(from player: HumanPlayer) -> Move? {
        var originRow, originCol, destRow, destCol : Int?
        
        originRow = readInt(withMessage: "\(player.name) please enter the origin row in which your piece is)")
        originCol = readInt(withMessage: "\(player.name) please enter the origin column in which your piece is)")
        destRow = readInt(withMessage: "\(player.name) please enter the destination row in which you want to move your piece)")
        destCol = readInt(withMessage: "\(player.name) please enter the destination column in which you want to move your piece)")
        
        //self.pieces[player.id][Animal.cat]?
        
        return Move(of: player.id, fromRow: originRow!, andFromColumn: originCol!, toRow: destRow!, andToColumn: destCol!)
    }

}
