<?php

/**
 * @copyright (c) Kufer Software GmbH, Loisachstrasse 4, D-84453 Mühldorf
 */

namespace Kufer\KuferTools\Teilnehmer\VorgesetzteAnmeldungenGenehmigen\BelegungsUebersicht;

use Kufer\Mail\EMail\EMailHTML;
use Kufer\Mail\Sender\EMailSenderFactory;
use Kufer\Web\Classes\Api\Belegung\OldBelegungStatusAenderungHandler;
use Kufer\Web\Classes\Api\VorgesetzterGenemigtBelegungAPI;
use Kufer\Web\Classes\Datamodul\DmzVorgesetzteGenemigtBelegung;
use Kufer\Web\Classes\Identifier\Identifier;
use Kufer\Web\KuferTools\Utils\Spezial\TeilnehmerVorgesetzterUtils;


class SaveBelegungenUseCase extends \Kufer\KuferTools\Basis\UseCase\ToolUseCase
{
  public $dbwBelegung;
  private $belegungHandler;

  public function __construct($request)
  {
    parent::__construct($request, new SaveBelegungenResponse());
    
    $this->dbwBelegung = new \DBWorkBelegung(1, true);
    $user = $this->getUser();
    $this->belegungHandler = new \Kufer\KuferTools\Utils\BelegungHandler\Belegungen4VorgesetzterAnhandBeziehung($this->toolSettings, $user->getTnrIdentifier());
  }

  public static function getToolSectionId()
  {
    return 359;
  }

  public static function getToolId()
  {
    return 67;
  }

  public function hasAccess($pToolSectionId = null)
  {
    if (!parent::hasAccess($pToolSectionId)) {
      return false;
    }

    if (!($this->getUser()->tnr > 0)) {
      return false;
    }

    return true;
  }

  public function action()
  {
    ini_set('max_execution_time', (string)(60 * 5));
    $belegungen = $this->getBearbeitbareBelegungen();
    list($geaenderteBelegungen, $belegungenAngenommenAbgelehnt) = $this->aktualisiereBelegungenAnhandRequest($belegungen);
    try {
      list($success, $newBelegungenAngenommenAbgelehnt) = $this->acceptOrDenyBelegungen($belegungen, $belegungenAngenommenAbgelehnt);
      if ($success) {
        
        
        
        list($this->response->success, $belegungenAngenommenAbgelehntKomplett) = $this->speicherBelegungen($geaenderteBelegungen, $belegungen, $belegungenAngenommenAbgelehnt);
        $emailResult = new \Kufer\Mail\Sender\Result\EMailSentResult(array());
        if ($this->response->success) {
          foreach ($belegungen as $belegung) {
            if (isset($newBelegungenAngenommenAbgelehnt[$belegung->id])) {
              $emailResult = $emailResult->merge($this->sendBenachrichtigungAngenommenAbgelehntAnTeilnehmer($newBelegungenAngenommenAbgelehnt[$belegung->id], $belegungenAngenommenAbgelehntKomplett[$belegung->id] ?? false, $belegung));
            }
          }
        }
      } else {
        $this->response->success = false;
      }
    } catch (\Exception $ex) {
      $this->response->success = false;
    }

    return $this->response;
  }

  
  protected function acceptOrDenyBelegungen(array $belegungen, array $belegungenAngenommenAbgelehnt): array
  {
    $newBelegungenAngenommenAbgelehnt = array();

    
    $oldVgbAry = \ArrayOperations::setAttributAsKey(VorgesetzterGenemigtBelegungAPI::getVorgesetzteZuBelegungenAndVorgesetzten(
      \ArrayOperations::mapAttribut($belegungen, 'id'),
      $this->getUser()->getTnrIdentifier()
    ), 'belegung_id');

    $tnId = $this->getUser()->getTnrIdentifier();
    $vgbAry = array();
    foreach ($belegungen as $belegung) {
      if (isset($belegungenAngenommenAbgelehnt[$belegung->id])
          && (!isset($oldVgbAry[$belegung->id]) || $oldVgbAry[$belegung->id]->genemigt != $belegungenAngenommenAbgelehnt[$belegung->id])) {
        $vgb = new DmzVorgesetzteGenemigtBelegung();
        $vgb->setVorgesetzterId($tnId);
        $vgb->belegung_id = $belegung->id;
        $vgb->genemigt = $belegungenAngenommenAbgelehnt[$belegung->id];
        $vgbAry[] = $vgb;

        $newBelegungenAngenommenAbgelehnt[$belegung->id] = $vgb->genemigt;
      }
    }

    if (!empty($vgbAry)) {
      return array(VorgesetzterGenemigtBelegungAPI::insert($vgbAry), $newBelegungenAngenommenAbgelehnt);
    } else {
      return array(true, array());
    }
  }

  private function sendBenachrichtigungAngenommenAbgelehntAnTeilnehmer(bool $angenommen, bool $komplett, \Belegung $belegung): \Kufer\Mail\Sender\Result\EMailSentResult
  {
    $viewModel = new \Kufer\Web\KuferTools\Teilnehmer\VorgesetzteAnmeldungenGenehmigen\SaveBelegungen\TnBenachrichtigungEMail\TnBenachrichtigungEMailViewModel();
    $viewModel->belegung = $belegung;
    $viewModel->angenommen = $angenommen;
    $viewModel->komplett = $komplett;
    $viewModel->vorgesetzter = \SessionOperations::getCurrentWebToolsTeilnehmer();

    $email = new \Kufer\Web\KuferTools\Teilnehmer\VorgesetzteAnmeldungenGenehmigen\SaveBelegungen\TnBenachrichtigungEMail\TnBenachrichtungEMailPresenter($viewModel);
    $email = new EMailHTML($email->getSubject(), $email->getContent());
    $email->addKuferToolsFooter('Akzeptieren und Ablehnen durch Vorgesetzte', $this->getUser(), $belegung);

    $sender = EMailSenderFactory::create();

    return $sender->sendFromTeilnehmerToTeilnehmer($email, $viewModel->vorgesetzter, array($viewModel->belegung->getTeilnehmer()));
  }

  
  protected function getBearbeitbareBelegungen()
  {
    $belegungen = $this->belegungHandler->getDatamoduleOhneFilter();

    return \ArrayOperations::setAttributAsKey(array_filter($belegungen, function(\Belegung $belegung) {
      if (TeilnehmerVorgesetzterUtils::isVorgesetztenTeilnehmerEnabled()) {
        if (!TeilnehmerVorgesetzterUtils::isKursGenehmigungspflichtig($belegung->getKurs())) {
          return false;
        }
      }

      return $belegung->status === 'P' && !\APIGebuehren::hasKursFortlaufendeGebuehren($belegung->knr);
    }), 'id');
  }

  private function aktualisiereBelegungenAnhandRequest($belegungen)
  {
    $belegungenAngenommenAbgelehnt = array();
    $geaenderteBelegungen = array();
    foreach ($belegungen as $belegung) {
      if (isset($this->request->bemerkungen[$belegung->id]) && $this->request->bemerkungen[$belegung->id] != $belegung->bemerkung) {
        $geaenderteBelegungen[$belegung->id] = clone($belegung);
        $geaenderteBelegungen[$belegung->id]->bemerkung = $this->request->bemerkungen[$belegung->id];
      }
      if (isset($this->request->genehmigungen[$belegung->id]) && in_array($this->request->genehmigungen[$belegung->id], array('ja', 'nein'))) {
        if (!isset($geaenderteBelegungen[$belegung->id])) {
          $geaenderteBelegungen[$belegung->id] = clone($belegung);
        }

        $angenommen = $this->request->genehmigungen[$belegung->id] == 'ja';
        $belegungenAngenommenAbgelehnt[$belegung->id] = $angenommen;

        
        if ($angenommen) {
          $geaenderteBelegungen[$belegung->id]->status = 'A';
        } else {
          $geaenderteBelegungen[$belegung->id]->status = 'S';
        }
      }
      if (isset($this->request->prioritaeten[$belegung->id]) && ($this->request->prioritaeten[$belegung->id] != $belegung->prioanm)) {
        if (!isset($geaenderteBelegungen[$belegung->id])) {
          $geaenderteBelegungen[$belegung->id] = clone($belegung);
        }
        $geaenderteBelegungen[$belegung->id]->prioanm = $this->request->prioritaeten[$belegung->id];
      }
    }

    return array($geaenderteBelegungen, $belegungenAngenommenAbgelehnt);
  }

  
  private function speicherBelegungen(array $belegungen, array $origBelegungen, array $belegungenAngenommenAbgelehnt): array
  {
    if (empty($belegungen)) {
      return array(true, array());
    }

    $oldHandler = new class($this->toolSettings, null, false, 'Vom Vorgesetzen abgelehnt', \DateTimeOperations::getDateNow(), array($this, 'sendBelegungStatusAendernMail'), array($this, 'postStatusSofortAenderungSuccessHook'), array($this, 'sendEMailAnWartenlistenTeilnehmer')) extends OldBelegungStatusAenderungHandler {
      protected $fnEMailAnWartenlistenTeilnehmer;

      public function __construct(\ToolSettings $toolSettings, ?string $alternativeEMail, bool $anmeldedatumNeuSetzen, ?string $stornogrund, ?string $austritt, $fnSendMail, $fnPostStatusSofortHook = null, $fnEMailAnWartenlistenTeilnehmer = null)
      {
        parent::__construct($toolSettings, $alternativeEMail, $anmeldedatumNeuSetzen, $stornogrund, $austritt, $fnSendMail, $fnPostStatusSofortHook);
        $this->fnEMailAnWartenlistenTeilnehmer = $fnEMailAnWartenlistenTeilnehmer;
      }

      public function handleStornoStatusAenderung(\Belegung $pBelegung, string $pStatusNeu): string
      {
        
        $success = \StornoAPI::handleStornoDmzOrDirektWithWarteliste(
          $pBelegung,
          $pStatusNeu,
          $this->stornogrund,
          $this->austritt,
          $this->fnEMailAnWartenlistenTeilnehmer
        );
        if ($success === \StornoAPI::SEND_SUCCESSFUL_PER_DIREKT || $success === \StornoAPI::SEND_SUCCESSFUL_PER_DMZ) {
          $statusCode = \BelegungAPI::STATUS_AENDERUNG_STORNO_ERFOLGREICH;
        
        } else { 
          $statusCode = \BelegungAPI::STATUS_AENDERUNG_STORNO_FEHLER;
        }

        return $statusCode;
      }

      public function handleEinfacheStatusAenderung(\Belegung $pBelegung, string $pStatusNeu): string
      {
        $statusAlt = $pBelegung->status;
        if ($pStatusNeu === 'S' && in_array($statusAlt, array(' ', '', 'A', 'P'))) {
          $result = $this->handleStornoStatusAenderung($pBelegung, $pStatusNeu);
          switch ($result) {
            default:
              return \BelegungAPI::STATUS_AENDERUNG_EINFACH_FEHLER;
            case \BelegungAPI::STATUS_AENDERUNG_STORNO_ERFOLGREICH:
              return \BelegungAPI::STATUS_AENDERUNG_EINFACH_ERFOLGREICH;
          }
        }

        $result = parent::handleEinfacheStatusAenderung($pBelegung, $pStatusNeu); 
        if ($result != \BelegungAPI::STATUS_AENDERUNG_EINFACH_ERFOLGREICH) {
          return $result;
        }

        return $result;
      }
    };

    
    foreach ($belegungen as $belegung) {
      if (isset($belegungenAngenommenAbgelehnt[$belegung->id])) {
        $genemigt = $belegungenAngenommenAbgelehnt[$belegung->id];
        $vorgesetzte = VorgesetzterGenemigtBelegungAPI::getVorgesetzteZuBelegung($belegung->id);
        if (is_null($vorgesetzte)) {
          return array(false, array());
        }

        $vgbAry = array_filter(
          $vorgesetzte,
          static function(DmzVorgesetzteGenemigtBelegung $vgb) use ($genemigt): bool {
            return $vgb->genemigt == $genemigt;
          }
        );

        
        if (count(TeilnehmerVorgesetzterUtils::getVorgesetztenIdsOfTeilnehmer($belegung->teilnehmer->getIdentifier())) > count($vgbAry)) {
          unset($belegungenAngenommenAbgelehnt[$belegung->id]);
          $belegung->status = $origBelegungen[$belegung->id]->status; 
                                                                      
        }
      }
    }

    

    $errorsAry = array(\BelegungAPI::BELEGUNG_BEARBEITEN_FEHLER,
      \BelegungAPI::STATUS_AENDERUNG_ANMELDUNG_FEHLER,
      \BelegungAPI::STATUS_AENDERUNG_STORNO_FEHLER,
      \BelegungAPI::STATUS_AENDERUNG_EINFACH_FEHLER,
      \BelegungAPI::STATUS_AENDERUNG_BELEGUNGSDATEN_NICHT_AKTUELL,
      \BelegungAPI::STATUS_AENDERUNG_PER_MAIL_FEHLER);

    $updateResult = \BelegungAPI::updateBelegungenWithStatus($oldHandler, $belegungen, $origBelegungen);
    $newBelegungenAngenommenAbgelehnt = array();
    foreach ($belegungenAngenommenAbgelehnt as $belId => $genemigt) {
      $status = $updateResult[$belId];
      if (!in_array($status, $errorsAry) && $status !== \BelegungAPI::BELEGUNG_BEARBEITEN_ERFOLGREICH) {
        $newBelegungenAngenommenAbgelehnt[$belId] = $genemigt;
      }
    }

    return array(empty(array_intersect($errorsAry, $updateResult)), $newBelegungenAngenommenAbgelehnt);
  }

  public function postStatusSofortAenderungSuccessHook(\Belegung $belegung, string $status): void
  {
  }

  public function sendEMailAnWartenlistenTeilnehmer(\Belegung $belegung, \Teilnehmer $teilnehmer): void
  {
    $viewModel = new \Kufer\Web\KuferTools\Teilnehmer\VorgesetzteAnmeldungenGenehmigen\SaveBelegungen\WartelisteTnBenachrichtigungEMail\WartelisteTnBenachrichtigungEMailViewModel();
    $viewModel->belegung = $belegung;
    $viewModel->receiver = $teilnehmer; 

    $email = new \Kufer\Web\KuferTools\Teilnehmer\VorgesetzteAnmeldungenGenehmigen\SaveBelegungen\WartelisteTnBenachrichtigungEMail\WartelisteTnBenachrichtungEMailPresenter($viewModel);
    $email = new EMailHTML($email->getSubject(), $email->getContent());
    $email->addKuferToolsFooter('Akzeptieren und Ablehnen durch Vorgesetzte', $this->getUser(), $belegung);

    $sender = EMailSenderFactory::create();

    if (!$sender->sendFromTeilnehmerToTeilnehmer($email, $viewModel->receiver, array($viewModel->belegung->getTeilnehmer()))->hasSentAllMails()) {
      \Logger::logg('Warteliste: Es konnte keine E-Mail an den Teilnehmer ' . $viewModel->receiver->getVarValue('name_ggf_vorname') . ' (' . $viewModel->receiver->id . ')' . ' gesendet werden!', 200);
    }
  }

  
  public function sendBelegungStatusAendernMail($pBelegung, $pHinderungsGruende, $pStatus)
  {
    $pStornogrund = 'Vom Vorgesetzen abgelehnt';
    $pAustritt = \DateTimeOperations::getDateNow();
    $pAnmeldedatumNeuSetzen = false;

    $person = \SessionOperations::getCurrentWebToolsPerson();

    $betreff = 'Statusänderung von ' . $pBelegung->teilnehmer->namevorname . ' in ' . $this->response->sprachSettings->Kurs['Singular_mit_Artikel']['Dativ'] . ' ' . $pBelegung->knr . ' (' . $pBelegung->kurs->getVarValue('kurzbez_titel') . ')';

    $body = 'Veranstalter ' . $person->name . ' ' . $person->vorname . ' möchte den Status ' . $this->response->sprachSettings->Teilnehmer['Singular_mit_Artikel']['Genitiv']
      . ' ' . $pBelegung->teilnehmer->getVarValue('name_vorname_ohne_komma') . ' in ' . $this->response->sprachSettings->Kurs['Singular_mit_Artikel']['Dativ'] . ' "'
      . $pBelegung->kurs->getVarValue('kurzbez_titel') . '" (Kurs-Nr. ' . $pBelegung->knr . ') ändern.';
    $body = \CleanOperations::cleanStringForHtml($body) . '<br><br>';

    $austrittDatum = '';
    if (isset($pAustritt)) {
      $austrittDatum = $pAustritt !== '' ? $pAustritt : \DateTimeOperations::getDateNow();
    }

    if ($pStornogrund != '') {
      $body .= 'Dabei wurde vom Veranstalter folgender Grund angegeben: ' . '<br>' . $pStornogrund . '<br><br>';
    }
    $body .= 'alter Status: ' . $pBelegung->status . '<br>';
    $body .= '<b>neuer Status</b>: ' . $pStatus . '<br>';
    $body .= $pAnmeldedatumNeuSetzen ? 'Das Anmeldedatum soll neu gesetzt werden.' . '<br><br>' : '<br>';
    $body .= $austrittDatum !== '' ? 'Austritt: ' . $austrittDatum . '<br><br>' : '<br>';
    $gruendeCount = count($pHinderungsGruende);
    if ($gruendeCount > 0) {
      $body .= ' Eine direkte Statusänderung konnte ';
      $body .= 'aus folgende' . ($gruendeCount == 1 ? 'm Grund' : 'n Gründen');
      $body .= ' nicht durchgeführt werden:' . '<br><br>';
      foreach ($pHinderungsGruende as $grund) {
        $body .= '- ' . $this->getText4HinderungsKonstanten($grund) . '<br>';
      }
    }
    $body .= '<br><br><i>Diese E-Mail wurde am ' . \DateTimeOperations::getDateNow() . ' um ' . \DateTimeOperations::getTimeNow() . ' aus den ' . KUFERTOOLS . ' versandt.</i>';

    $mail = new \Kufer\Mail\EMail\EMailHTML($betreff, $body);
    $mail->addKuferToolsFooter('Statusänderung eines Teilnehmers im Kurs', $this->getUser(), $pBelegung->kurs);

    $sender = \Kufer\Mail\Sender\EMailSenderFactory::create();
    $result = $sender->sendFromToolsUserToEinrichtung($mail, $this->getUser());

    return $result->hasSentAnyMails();
  }

  
  private function getText4HinderungsKonstanten(string $pHinterungsGrund): string
  {
    $text = '';
    switch ($pHinterungsGrund) {
      case \BelegungAPI::STATUS_AENDERUNG_HINDERUNG_TEIL_EINER_MEHRFACHANMLEDUNG:
        $text = $this->response->sprachSettings->Teilnehmer['Singular_mit_Artikel']['Nominativ'] . ' gehört zu einer Mehrfach- oder Firmenanmeldung';
        break;
      case \BelegungAPI::STATUS_AENDERUNG_HINDERUNG_TEIL_EINER_ELTERN_KIND_ANMELDUNG:
        $text = 'Zu dieser Anmeldung gehören Kinderanmeldungen';
        break;
    }

    return $text;
  }
}

class SaveBelegungenRequest extends \Kufer\KuferTools\Basis\Uebersicht\UebersichtRequest
{
  public $bemerkungen;
  public $genehmigungen;
}

class SaveBelegungenResponse extends \Kufer\KuferTools\Basis\Uebersicht\UebersichtRequest
{
  public $success;
}