<?php

namespace SpaceDrift;


use System\Session;

class Game
{
    private static $names = [
        'Alice',
        'Bob',
        'Charlie',
        'Dexter',
        'Exter'
    ];

    private static $roles = [
        'Trooper',
        'Captain',
        'Engineer',
        'Biologist',
        'Physicist'
    ];

    private static $objects = [
        'Blaster',
        'Big Hat',
        'Wrench',
        'Syringe',
        'Remote'
    ];

    private static $races = [
        'Human',
        'Human',
        'Human',
        'Human',
        'Android',
    ];

    public static $rooms = [
        'Science Lab',
        'Main Deck',
        'Armory',
        'Teleport Room',
        'Loading Bay'
    ];

    /**
     * Private construct so nobody else can instance it
     *
     */
    private function __construct()
    {

    }

    /**
     * Call this method to get singleton
     *
     * @return Game
     */
    public static function Instance()
    {
        static $inst = null;
        if ($inst === null) {
            $inst = new Game();
        }
        return $inst;
    }

    private function getDb()
    {
        return new \PDO('mysql:host=localhost;dbname=spacedrift', 'root');
    }

    public function getPlayerList()
    {
        $db = $this->getDb();
        $sql = 'SELECT character_name FROM game';
        return $db->query($sql)->fetchAll(\PDO::FETCH_COLUMN);
    }

    public function addPlayer($character)
    {
        $db = $this->getDb();
        $stmt = $db->prepare("SELECT character_name FROM game WHERE CHARACTER_NAME = :characterName");
        $stmt->bindParam(':characterName', $character);
        $check = $stmt->execute() or die("cannot execute the query" . implode('<br>', $stmt->errorInfo()));

        if (!$stmt || $stmt->rowCount() > 0) {
            return false;
        } else {
            $game = new self();
            $_SESSION['myname'] = $character;
            $stmt = $db->prepare("INSERT INTO game (character_name) VALUES (:characterName)");
            $stmt->bindParam(':characterName', $character);
            $stmt->execute();
            return count($game->getPlayerList());
        }
    }

    public function deleteGame()
    {
        $db = $this->getDb();
        $sql = 'DELETE FROM game';
        $db->exec($sql);
        unset($_SESSION['myname']);
    }

    public static function doAction($from, $clients, $action)
    {
        switch ($action->call) {
            case 'lobby': {
                self::manageLobby($from, $clients, $action->param);
                break;
            }
            case 'timer' : {
                self::getTimerStart($clients);
                break;
            }
            case 'who-am-i': {
                self::whoAmI($from, $clients);
                break;
            }
            default : {
            //TODO: Errore
            }
        }
    }

    public static function whoAmI()
    {
        return isset($_SESSION['myname']) ? $_SESSION['myname'] : "none";
    }

    public static function manageLobby($from, $clients, $name)
    {
        $game = new self();
        $result = $game->addPlayer($name);

        foreach ($clients as $client) {
            $dsp = new Dispatcher();

            if ($from !== $client) {
                if ($result) {
                    $dsp->addMessage(new Message('join', 'event', $name, $client->resourceId, $name . " has joined the lobby"));
                }
            } else {
                if ($result) {
                    $dsp->addMessage(new Message('join', 'success', $name, $client->resourceId, "you joined the lobby as " . $name));
                } else {
                    $dsp->addMessage(new Message('join', 'deny', $from->resourceId, $client->resourceId, "you cannot join the lobby as " . $name));
                }
            }

            if($result == 2){
                $start = $game->setTimerStart();
                $game->gameStart();
                $dsp->addMessage(new Message('game', 'start', 0, $client->resourceId, $start));
            }

            if ($dsp->count()) {
                $client->send($dsp->toJSON());
            }
        }
    }

    public static function setTimerStart()
    {
        $game = new self();
        $db = $game->getDb();
        $microtime = microtime(true);
        $sql = "REPLACE INTO timer(start) VALUES ($microtime)";
        $db->query($sql) or die("cannot execute the query" . implode('<br>', $db->errorInfo()));
        return $microtime;
    }

    public static function getTimerStart($clients){
        $game = new self();
        $db = $game->getDb();
        $start = $db->query("SELECT start FROM timer")->fetch(\PDO::FETCH_COLUMN);

        foreach ($clients as $client) {
            $dsp = new Dispatcher();
            $dsp->addMessage(new Message('timer', 'start', 0, $client->resourceId, $start));
            echo $dsp->toJSON() . "\n";
            $client->send($dsp->toJSON());
        }
    }

    public static function gameStart(){
        $game = new self();
        $db = $game->getDb();

        shuffle(self::$roles);
        shuffle(self::$objects);
        shuffle(self::$races);
        shuffle(self::$rooms);

        $sql = "UPDATE game SET role = :role, object = :object, race = :race, room = :room WHERE character_name = :name";
        $stmt = $db->prepare($sql);
        foreach(self::$names as $k => $name){
            $stmt->execute([
                ':role' => self::$roles[$k],
                ':object' => self::$objects[$k],
                ':race' => self::$races[$k],
                ':room' => self::$rooms[$k],
                ':name' => $name
            ]) or die("cannot execute the query" . implode('<br>', $stmt->errorInfo()));
        }
    }

    public static function getPlayer($name){
        $game = new self();
        $db = $game->getDb();
        $sql = "SELECT * FROM game WHERE character_name = '$name'";
        return $db->query($sql)->fetch(\PDO::FETCH_OBJ);
    }

    public static function movePlayer(){

    }
} 