<?php
class AdminModel
{

    private EnigmeGateway $enigme_gateway;
    private ResoudreGateway $resoudre_gateway;
    private PartieGateway $partie_gateway;
    private Nettoyage $nettoyage;
    private Validation $validation;

    function __construct()
    {
        global $error, $view, $rep;
        $this->enigme_gateway = new EnigmeGateway();
        $this->resoudre_gateway = new ResoudreGateway();
        $this->partie_gateway = new PartieGateway();
        $this->nettoyage = new Nettoyage();
        $this->validation = new Validation();
    }

    public function  addNewEnigmeSolo(string $nom,string $enonce,string $aide,string $rappel,string $exemple,string $test,string $solution, string $prompt) : Enigme
    {
        $last = $this->enigme_gateway->findLastEnigmaByOrdre();
        if ($last != null){
            $ordre = $last[0]->getOrdre() + 1;
        } else {
            $ordre = 1;
        }
        $enigme = new Enigme(1,$nom, $enonce, $aide, $rappel, $exemple, $solution, $test, $ordre, 0, 0, $prompt);
        $this->enigme_gateway->insert($enigme);
        $tabEnigme = $this->enigme_gateway->findLastEnigma();
        $js = fopen("View/src/JS/$nom.js", "w");
        if (is_resource($js)) {
            fwrite($js, "//~ Function that test the user code

async function submit(){
  var test = editor.getValue()+`\\n\n". $solution . "\n". $test . "\n`;
  exec(\"print ('True')\", \"code\"); 
  exec(test, \"solution\");
  result.innerHTML = \"Test en cours...\";
  await new Promise(r => setTimeout(r, 1500));
  check();
}");
            fclose($js);
          } else {
            throw new Exception("Impossible d'ouvrir le fichier");
          }
        return $tabEnigme[0];
    }
    public function  addNewEnigmeMulti(string $nom,string $enonce,string $aide,string $rappel,string $exemple,string $test,string $solution, string $prompt, int $points, int $tempsDeResolution) : Enigme
    {
        $enigme = new Enigme(1,$nom, $enonce, $aide, $rappel, $exemple, $solution, $test, 0, $tempsDeResolution, $points, $prompt);
        $this->enigme_gateway->insert($enigme);
        $tabEnigme = $this->enigme_gateway->findLastEnigma();
        $js = fopen("View/src/JS/$nom.js", "w");
        if (is_resource($js)) {
            fwrite($js, "//~ Function that test the user code

async function submit(){
  var test = editor.getValue()+`\\n\n". $solution . "\n". $test . "\n`;
  exec(\"print ('True')\", \"code\"); 
  exec(test, \"solution\");
  result.innerHTML = \"Test en cours...\";
  await new Promise(r => setTimeout(r, 1500));
  check();
}");
            fclose($js);
          } else {
            throw new Exception("Impossible d'ouvrir le fichier");
          }
        return $tabEnigme[0];
    }

    private function majOrdreAfterDelete(int $ordre){
      $lesEnigmes = $this->enigme_gateway->findSoloEnigma();
      if ($lesEnigmes == null) {
        return;
      }
      $lastOrdre = $this->enigme_gateway->findLastEnigmaByOrdre()[0]->getOrdre();
      if ($ordre > $lastOrdre) {
        return;
      }
      foreach ($lesEnigmes as $enigme) {
        if ($enigme->getOrdre() <= $ordre) {
          continue;
        }
        $enigme->setOrdre($enigme->getOrdre()-1);
        $this->enigme_gateway->update($enigme);
      }
    }

    public function deleteEnigme(int $id) : void
    {
      $enigme = $this->getEnigmeById($id);
      $nom = $enigme->getNom();
      $ordre = $enigme->getOrdre();
      $this->resoudre_gateway->deleteByEnigme($id);
      $this->partie_gateway->deleteByEnigme($id);
      $this->enigme_gateway->delete($id);
      unlink('View/src/JS/'.$nom.'.js');
      $this->majOrdreAfterDelete($ordre);
    }

    public function getEnigmesSolo() : array
    {
        return $this->enigme_gateway->findSoloEnigma();
    }
    public function getEnigmesMulti() : array
    {
        return $this->enigme_gateway->findMultiEnigma();
    }
    public function getEnigmeById (int $id) : Enigme
    {
        return $this->enigme_gateway->findById($id)[0];
    }
    public function editEnigme(int $id, string $nom,string $enonce,string $aide,string $rappel,string $exemple,string $test,string $solution, string $prompt, int  $points, int $tempsDeResolution) : Enigme
    {
        $old = $this->enigme_gateway->findById($id)[0];
        $ordre = $old->getOrdre();
        $nom = trim($nom);
        $enonce = trim($enonce);
        $aide = trim($aide);
        $rappel = trim($rappel);
        $exemple = trim($exemple);
        $test = trim($test);
        $solution = trim($solution);
        $prompt = trim($prompt);
        $enigme = new Enigme($id,$nom, $enonce, $aide, $rappel, $exemple, $solution, $test, $ordre, $tempsDeResolution, $points, $prompt);
        $this->enigme_gateway->update($enigme);
        $js = fopen("View/src/JS/$nom.js", "w");
        if (is_resource($js)) {
            fwrite($js, "//~ Function that test the user code

async function submit(){
  var test = editor.getValue()+`\\n\n". $solution . "\n". $test . "\n`;
  exec(\"print ('True')\", \"code\"); 
  exec(test, \"solution\");
  result.innerHTML = \"Test en cours...\";
  await new Promise(r => setTimeout(r, 1500));
  check();
}");
            fclose($js);
            if ($old->getNom() != $nom){
              unlink('View/src/JS/'.$old->getNom().'.js');
            }
          } else {
            throw new Exception("Impossible d'ouvrir le fichier");
          }
        return $enigme;
    }

    private function checkOrdre(array $lesOrdres){
      $lesNombres = array();
      foreach ($lesOrdres as $ordre) {
          if ($ordre[1] < 1) {
            throw new Exception("Aucune énigme ne peut avoir un ordre inférieur à 1");
          }
          $lesNombres[] = $ordre[1];
      }
      sort($lesNombres);
      if ($lesNombres[0] != 1) {
        throw new Exception("La première énigme doit avoir un ordre de 1");
      }
      $last = end($lesNombres);
      $i = 0;
      while ($i < $last) {
          if ($lesNombres[$i] != $i+1) {
            throw new Exception("L'ordre des énigmes doit être consécutif");
          }
          $i++;
      }
      return true;
  }
    
    public function modifOrdre(array $lesOrdres){
      if (!$this->checkOrdre($lesOrdres)){
        throw new Exception("Les ordres ne sont pas corrects");
      }
      foreach ($lesOrdres as $ordre){
        $enigme = $this->enigme_gateway->findById($ordre[0])[0];
        $enigme->setOrdre($ordre[1]);
        $this->enigme_gateway->update($enigme);
      }
    }
}