<?php
use Random\Engine;
class PartieGateway
{
    private Connection $con;

    /**
     * @param Connection $con
     */
    public function __construct()
    {
        global $dsn, $rep, $vues, $error;
        try {
            $con = new Connection($dsn);
            $this->con = $con;
        } catch (Exception $e) {
            $error = $e->getMessage();
            require($rep . $vues['erreur']);
        }
    }

    public function partieInQueueExists(): bool
    {
        $query = "SELECT count(*) FROM PARTICIPER WHERE etat = 0";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        if ($results[0]['count(*)'] == 0)
            return false;
        else
            return true;
    }

    public function findPartieMaxId(): int
    {
        $query = "SELECT max(id) FROM Partie";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        if ($results[0]['max(id)'] == NULL)
            return 0;
        else
            return $results[0]['max(id)'];
    }

    public function rejoindrePartieMulti(int $idPartieInQueue, array $tabEnigme): Partie
    {
        $partie = PartieFactory::createPartieMulti($idPartieInQueue, $tabEnigme);
        return $partie;
    }

    public function findPartieInQueue()
    {
        $query = "SELECT partie
        FROM Participer
        WHERE etat=0
        LIMIT 1";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        if (empty($results)) {
            return 0;
        }
        return $results[0]['partie'];
    }

    public function creerPartieSolo(Utilisateur $utilisateur)
    {
        $query = "SELECT * FROM Enigme
        WHERE points IS NULL OR points = 0";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        $query = "SELECT max(p.id)
        FROM PARTIE p;";
        $this->con->executeQuery($query);
        $max = $this->con->getResults()[0]["max"];
        $partie = PartieFactory::createPartieSolo($max, $results);
        $query = "INSERT INTO Partie VALUES (:idPartie,:idEnigme)";
        $this->con->executeQuery($query, array(':idPartie' => array($partie->getIdPartie(), SQLITE3_INTEGER)));
        foreach ($partie->getListeEnigme() as $Enigme) {
            $query = "INSERT INTO Contenir VALUES (:idPartie, :idEnigme)";
            $this->con->executeQuery($query, array(
                ':idPartie' => array($partie->getIdPartie(), SQLITE3_INTEGER),
                ':idEnigme' => array($Enigme->getIdEnigme(), SQLITE3_INTEGER)
            )
            );
        }
        foreach ($partie->getListeEnigme() as $Enigme) {
            $query = "INSERT INTO Contenir VALUES (:idPartie, :idEnigme)";
            $this->con->executeQuery($query, array(
                ':idPartie' => array($partie->getIdPartie(), SQLITE3_INTEGER),
                ':idEnigme' => array($Enigme->getIdEnigme(), SQLITE3_INTEGER)
            )
            );
        }
        $query = "INSERT INTO Participer VALUES (:idPartie, :idUtilisateur, TRUE)";
        $this->con->executeQuery($query, array(
            'idPartie' => array($partie->getIdPartie(), SQLITE3_INTEGER),
            'idUtilisateur' => array($utilisateur->getEmail(), SQLITE3_INTEGER)
        )
        );
    }

    public function findLastPartie(): Partie
    {
        $query = "SELECT * FROM Partie ORDER BY id DESC LIMIT 1";
        $this->con->executequery($query);
        $results = $this->con->getResults();
        $row = $results[0];
        $partie = new Partie($row['id'], array());
        $date = new DateTime($row['dateDebut']);
        $partie->setDatePartie($date);
        return $partie;
    }

    public function createPartie(Enigme $enigme, Utilisateur $utilisateur)
    {
        $query = "INSERT INTO Partie VALUES (NULL,:date)";
        $currentDate = date('Y-m-d H:i:s');
        $this->con->executeQuery($query, array(
            "date" => array($currentDate, SQLITE3_TEXT)
        )
        );
        $partie = $this->findLastPartie();
        $query = "INSERT INTO Contenir VALUES (:partie,:idEnigme,NULL)";
        $this->con->executeQuery($query, array(
            "partie" => array($partie->getIdPartie(), SQLITE3_INTEGER),
            "idEnigme" => array($enigme->getIdEnigme(), SQLITE3_INTEGER)
        )
        );
        $query = "INSERT INTO Participer VALUES (:partie,:utilisateur,NULL)";
        $this->con->executeQuery($query, array(
            "partie" => array($partie->getIdPartie(), SQLITE3_INTEGER),
            "utilisateur" => array($utilisateur->getEmail(), SQLITE3_TEXT)
        )
        );
    }

    public function createPartieMulti(array $lesEnigmes, string $mailUtilisateur)
    {
        $query = "INSERT INTO Partie VALUES (NULL,:date)";
        $currentDate = date('Y-m-d H:i:s');
        $this->con->executeQuery($query, array(
            "date" => array($currentDate, SQLITE3_TEXT)
        )
        );
        $partie = $this->findLastPartie();
        $query = "INSERT INTO Contenir VALUES (:partie,:idEnigme,:index)";
        $i = 1;
        foreach ($lesEnigmes as $enigme) {
            $this->con->executeQuery($query, array(
                "partie" => array($partie->getIdPartie(), SQLITE3_INTEGER),
                "idEnigme" => array($enigme->getIdEnigme(), SQLITE3_INTEGER),
                "index" => array($i, SQLITE3_INTEGER),
            )
            );
            $i++;
        }
        $query = "INSERT INTO Participer VALUES (:partie,:utilisateur,0)";
        $this->con->executeQuery($query, array(
            "partie" => array($partie->getIdPartie(), SQLITE3_INTEGER),
            "utilisateur" => array($mailUtilisateur, SQLITE3_TEXT)
        )
        );
    }

    public function delete(int $idPartie)
    {
        $query = "DELETE FROM Contenir WHERE partie = :enigmeId";
        $this->con->executeQuery($query, array(':enigmeId' => array($idPartie, SQLITE3_INTEGER)));
        $query = "DELETE FROM Participer WHERE partie = :enigmeId";
        $this->con->executeQuery($query, array(':enigmeId' => array($idPartie, SQLITE3_INTEGER)));
        $query = "DELETE FROM Partie WHERE id = :idPartie";
        $this->con->executeQuery($query, array(':idPartie' => array($idPartie, SQLITE3_INTEGER)));
    }

    public function deleteByEnigme(int $enigmeId)
    {
        $query = "SELECT partie FROM Contenir WHERE enigme = :enigmeId";
        $this->con->executeQuery($query, array(':enigmeId' => array($enigmeId, SQLITE3_INTEGER)));
        $results = $this->con->getResults();

        $query = "DELETE FROM Contenir WHERE enigme = :enigmeId";
        $this->con->executeQuery($query, array(':enigmeId' => array($enigmeId, SQLITE3_INTEGER)));

        foreach ($results as $row) {
            $query = "DELETE FROM Participer WHERE partie = :partieId";
            $this->con->executeQuery($query, array(':partieId' => array($row['partie'], SQLITE3_INTEGER)));
            $query = "DELETE FROM Partie WHERE id = :partieId";
            $this->con->executeQuery($query, array(':partieId' => array($row['partie'], SQLITE3_INTEGER)));
        }
    }

    public function findPartieHistory(): array
    {
        $query = "SELECT * FROM Partie";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        $query = "SELECT max(p.id)
        FROM PARTIE p;";
        $this->con->executeQuery($query);
        $max = $this->con->getResults()[0]["max"];
        $listePartieHistory = array();
        foreach ($results as $row) {
            $query = "SELECT e.* FROM Enigme e,Contenir c,Partie p
            WHERE p.id = c.partie
            AND c.enigme = e.id
            AND c.enCours = false;
            AND p.partie = :idPartie";
            $this->con->executeQuery($query, array(
                "idPartie" => array($row["idPartie"], SQLITE3_INTEGER)
            )
            );
            $historiquePartie = $this->con->getResults();
            $listePartieHistory[] = PartieFactory::createPartieHistory($row["idPartie"], $historiquePartie);
        }
        return $listePartieHistory;
    }
    public function findPartieByEnigmeId(int $enigmeId): Partie
    {
        $query = "SELECT * FROM Partie p, Resoudre r
        WHERE r.enigme = :enigmeId
        AND r.partie = p.id";
        $this->con->executeQuery($query, array(
            ':enigmeId' => array($enigmeId, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $row = $results[0];
        $partie = new Partie($row['id'], array());
        $date = new DateTime($row['dateDebut']);
        $partie->setDatePartie($date);
        return $partie;
    }

    public function addToPartie(string $mailUtilisateur, int $idPartie)
    {
        global $playerNumberPerGame;
        $player = $this->getPlayerNumber($idPartie);
        if ($player == $playerNumberPerGame) {
            throw new Exception("La partie est pleine");
        }
        if ($player + 1 == $playerNumberPerGame) {
            $query = "INSERT INTO Participer VALUES (:partie,:utilisateur,1)";
            $this->con->executeQuery($query, array(
                "partie" => array($idPartie, SQLITE3_INTEGER),
                "utilisateur" => array($mailUtilisateur, SQLITE3_TEXT)));
                
            $query = "UPDATE Participer 
            SET etat = 1
            WHERE partie = :partie 
            AND utilisateur != :utilisateur";
            $this->con->executeQuery($query, array(
                "partie" => array($idPartie, SQLITE3_INTEGER),
                "utilisateur" => array($mailUtilisateur, SQLITE3_TEXT)));
        }
        else {
            $query = "INSERT INTO Participer VALUES (:partie,:utilisateur,0)";
            $this->con->executeQuery($query, array(
                    "partie" => array($idPartie, SQLITE3_INTEGER),
                    "utilisateur" => array($mailUtilisateur, SQLITE3_TEXT)));
        }
    }
    public function getPlayerNumber(int $idPartie): int
    {
        $query = "SELECT count(*) FROM Participer WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $row = $results[0];
        return $row['count(*)'];
    }
    public function getEtat($idPartie){
        $query = "SELECT etat FROM Participer WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        foreach ($results as $row){
            if($row['etat'] == 2){
                return 2;
            }
            if($row['etat'] == 1){
                return 1;
            }
        }
        return 0;
    }

    public function getLesMailJoueurs($idPartie){
        $query = "SELECT utilisateur FROM Participer WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $lesJoueurs = array();
        foreach ($results as $row){
            $lesJoueurs[] = $row['utilisateur'];
        }
        return $lesJoueurs;
    }
    public function getLesIdEnigmes($idPartie){
        $query = "SELECT enigme FROM Contenir WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $lesEnigmes = array();
        foreach ($results as $row){
            $lesEnigmes[] = $row['enigme'];
        }
        return $lesEnigmes;
    }

    public function findEnigmeIdInPartieWithIndex($idPartie, $index) : int{
        $query = "SELECT * FROM Contenir WHERE partie = :idPartie AND indexEnigme = :index";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER),
            "index" => array($index, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $row = $results[0];
        return $row['enigme'];
    }

    public function findAllEnigmeIdInPartie ($idPartie) : array{
        $query = "SELECT * FROM Contenir WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $lesEnigmes = array();
        foreach ($results as $row){
            $lesEnigmes[] = $row['enigme'];
        }
        return $lesEnigmes;
    }
    public function getDateDebut($idPartie) : DateTime{
        $query = "SELECT dateDebut FROM Partie WHERE id = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
        $results = $this->con->getResults();
        $date = new DateTime ($results[0]['dateDebut']);
        return $date;
    }
    public function endGame(int $idPartie){
        $query = "UPDATE Participer SET etat = 2 WHERE partie = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
    }
    public function launchGame(int $idPartie){
        $query = "UPDATE Participer SET etat=1 WHERE etat=0 AND partie=:partie";
        $this->con->executeQuery($query,array(
            'partie' => array($idPartie,SQLITE3_INTEGER)));
    }
    public function checkUserIsInPartie(string $mailUtilisateur) : bool {
        $query = "SELECT * FROM Participer WHERE utilisateur = :mailUtilisateur AND etat != 2";
        $this->con->executeQuery($query, array(
            "mailUtilisateur" => array($mailUtilisateur, SQLITE3_TEXT)
        )
        );
        $results = $this->con->getResults();
        if(count($results) == 0 || $results == null){
            return false;
        }
        return true;
    }
    public function majDateDebut(int $idPartie){
        $query = "UPDATE Partie SET dateDebut = :dateDebut WHERE id = :idPartie";
        $this->con->executeQuery($query, array(
            "idPartie" => array($idPartie, SQLITE3_INTEGER),
            "dateDebut" => array(date("Y-m-d H:i:s"), SQLITE3_TEXT)
        )
        );
    }
    public function quitQueue(string $mailUtilisateur,int $idPartie){
        $query = "DELETE FROM Participer 
        WHERE utilisateur = :mailUtilisateur 
        AND partie = :idPartie";
        $this->con->executeQuery($query, array(
            "mailUtilisateur" => array($mailUtilisateur, SQLITE3_TEXT),
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
    }

    public function quitGame(string $mailUtilisateur,int $idPartie){
        $query = "UPDATE Participer SET etat = 2 WHERE utilisateur = :mailUtilisateur AND partie = :idPartie";
        $this->con->executeQuery($query, array(
            "mailUtilisateur" => array($mailUtilisateur, SQLITE3_TEXT),
            "idPartie" => array($idPartie, SQLITE3_INTEGER)
        )
        );
    }
    public function showAll(): void
    {
        $query = "SELECT * FROM Partie";
        $this->con->executeQuery($query);
        $results = $this->con->getResults();
        foreach ($results as $row) {
            echo $row['idPartie'] . '</br>';
        }
    }
}