//
//  MatchmakingHelper.swift
//  GoldWars
//
//  Created by Chauntalle Schüle, Ömer Özel, Eray Kör on 03.05.20.
//  Copyright © 2020 SP2. All rights reserved.
//

import GameKit

protocol GameKitHelperDelegate {
    func matchStarted()
    func matchEnded()
    func matchReceivedData(match: GKMatch, data: NSData,
                           fromPlayer player: String)
    
}
/*
 Diese Klasse wird für das Matchmaking über das Gamecenter gebraucht
 @param: delegate: erhält alle Multiplayerevents
 @param: mpMatch: repräsentiert das Netzwerk, alle Mitspieler besitzen ein gemeinsames Spiel
 @param: viewController: ist nicht der ViewController des Gamecenters, sondern des Spiels
 @param: mpMatchStarted: gibt an, ob ein Match schon gestartet wurde
 @param: isServer: gibt an, ob der local player, als der Server fungiert
 @param: spieler1: ist immer der Spieler, der der Server ist
 @param: spieler2: ist immer der Spieler, der der Client ist
 @param: sharedInstance: ist eine geteilte Instanz für alle Spieler
 */
class MatchmakingHelper: NSObject, GKMatchmakerViewControllerDelegate, GKMatchDelegate {
    
    var delegate: GameKitHelperDelegate?
    var mpMatch: GKMatch?
    var viewController: UIViewController?
    var mpMatchStarted: Bool
    var isServer: Bool
    var spieler1: GKPlayer?
    var nameSpieler1 = ""
    var menusc: MenuScene?
    let localPlayer: GKLocalPlayer = GKLocalPlayer.local
    
    static let sharedInstance = MatchmakingHelper()
    
    
    static var isAuthenticated: Bool{
        return GKLocalPlayer.local.isAuthenticated
    }
    
    override init() {
        mpMatchStarted = false
        isServer = false
        super.init()
    }
    
    /*
     Diese Methode wechselt von der MenuScene zum GameCenter ViewController. Die Spieler werden hier gesucht und gematcht. Mit minplayers/maxplayers kann bestimmt werden, wie viele Spieler insgesamt zusammen miteinander spielen.
     */
    func presentMatchmaker(scene: MenuScene) {
        menusc = scene
        guard GKLocalPlayer.local.isAuthenticated else {
            return
        }
        let request = GKMatchRequest()
        
        request.minPlayers = 2
        request.maxPlayers = 2
        request.inviteMessage = "Willst du GoldWars spielen?"
        
        let matchmakerVC = GKMatchmakerViewController.init(matchRequest: request)
        matchmakerVC!.matchmakerDelegate = self
        viewController?.present(matchmakerVC!, animated: true, completion: nil)
    }
    
    /*
     Der User hat die Verbindung mit "Abbrechen" unterbrochen. GameCenter MatchMaking wird beendet.
    */
    func matchmakerViewControllerWasCancelled(_ viewController: GKMatchmakerViewController) {
        viewController.dismiss(animated: true, completion: nil)
        delegate?.matchEnded()
    }
    
    /*
    Wenn GameCenter kein match erstellen kann, wird der viewcontroller dismissed.
    */
    func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFailWithError error: Error) {
        viewController.dismiss(animated: true, completion: nil)
        print("Error finding match", error.localizedDescription)
        delegate?.matchEnded()
    }
    
    /*
     Gamecenter hat erfolgreich ein Match gefunden, das Spiel kann gestartet werden.
     expectedPlayerCount: Die verbleibende Anzahl von Spielern, die sich noch nicht mit dem Spiel verbunden haben
     z.B 0 gibt an, dass keine weiteren Spieler benötigt werden um das Match zu starten
    */
    func matchmakerViewController(_ viewController: GKMatchmakerViewController, didFind match: GKMatch) {
        viewController.dismiss(animated: true, completion: nil)
        mpMatch = match
        match.delegate = self
        if !mpMatchStarted && match.expectedPlayerCount == 0 {
            startMatch()
        }
    }
    
    /*
    Vom match erhaltene Spielerdaten
    */
    private func match(match: GKMatch!, didReceiveData data: NSData!,fromPlayer playerID: String!) {
        if mpMatch != match { return }
        delegate?.matchReceivedData(match: match, data: data, fromPlayer: playerID)
        
    }
    
    /*
     Verbindung/Matchmaking ist fehlgeschlagen
     */
    private func match(match: GKMatch!, didFailWithError error: NSError!) {
        if mpMatch != match {
            return
        }
        mpMatchStarted = false
        delegate?.matchEnded()
    }
    
    /*
     Wird beim ändern des States/Zustands des Spielers aufgerufen udn gibt dessen Zustand zurück.
     */
    func match(_ match: GKMatch, player: GKPlayer, didChange state: GKPlayerConnectionState) {
        if mpMatch != match {
            return
        }
        
        switch (state) {
        case GKPlayerConnectionState.connected:
            if (!mpMatchStarted && match.expectedPlayerCount == 0) {
                startMatch()
            }
        case GKPlayerConnectionState.disconnected:
            mpMatchStarted = false
            delegate?.matchEnded()
        default:
            delegate?.matchEnded()
        }
    }
    
    /*
    Ein Spieler wird als Host für das Match gewählt. Dieser ist Spieler 1. Im Anschluss wird die GameScene geladen.
    */
    func startMatch() {

        mpMatch!.chooseBestHostingPlayer(completionHandler: {
            (player) in
            
            self.mpMatchStarted = true

            if player == GKLocalPlayer.local {
                self.isServer = true
                self.spieler1 = player
                self.nameSpieler1 = self.spieler1!.displayName
                
            } else {
                self.isServer = false
            }
            
            self.delegate?.matchStarted()
            self.menusc!.loadScene(scene: GameScene(size: self.menusc!.size))
        })
    }

    
    /*
     Trennt die Verbindung vom Match
     */
    func disconnect() {
        if mpMatch != nil {
            mpMatch?.disconnect()
        }
    }
}
