<?php
/**
 * @copyright (c) Kufer Software GmbH, Oderstraße 7, D-84453 Mühldorf
 */

namespace Kufer\Web\KuferTools\Oeffentlich\LoginAnfordern\SendeAutoLoginAnfordern;

use Kufer\Web\KuferTools\Oeffentlich\LoginAnfordern\SendeLoginAnfordern\SendeLoginAnfordernEMailPresenter;
use Kufer\Web\KuferTools\Oeffentlich\LoginAnfordern\SendeLoginAnfordern\SendeLoginAnfordernEMailViewModel;
use Kufer\Web\KuferTools\Oeffentlich\LoginAnfordern\SendeLoginAnfordern\SendeLoginAnfordernUseCase;
use Kufer\Web\KuferTools\Oeffentlich\LoginAnfordern\Utils\HandleLoginAnfordernEingaben;
use Kufer\Web\KuferTools\Oeffentlich\PasswortAnfordern\Utils\HandlePasswortAnfordernEingaben;

class SendeAutoLoginAnfordernUseCase extends \Kufer\Web\KuferTools\Basis\UseCase\UseCase
{
  public const DOZ_AUTO_LOGIN = 'dozent';
  public const TN_AUTO_LOGIN = 'teilnehmer';

  
  private $toolSettings;

  
  private $allowedToolGroups;

  public function __construct($request, $pToolSettings)
  {
    parent::__construct($request, new SendeAutoLoginAnfordernResponse());
    $this->toolSettings = $pToolSettings;
    $this->allowedToolGroups = \DBWorkTools::getDefaultInstance()->getBenGruppen4Tools();
  }

  public function hasAccess($pToolSectionId = null)
  {
    if (!$this->isDozentAllowed()
      && !$this->isTeilnehmerAllowed()) {
      return false;
    }

    if ($this->getBenutzergruppe() === static::DOZ_AUTO_LOGIN && !$this->isDozentAllowed()) {
      return false;
    }

    if ($this->getBenutzergruppe() === static::TN_AUTO_LOGIN && !$this->isTeilnehmerAllowed()) {
      return false;
    }

    if (!in_array($this->getBenutzergruppe(), array(static::DOZ_AUTO_LOGIN, static::TN_AUTO_LOGIN))) {
      return false;
    }

    if (!$this->request->isXsrfOk && !$this->request->isRefresh) {
      return false;
    }

    return true;
  }

  private function isDozentAllowed(): bool
  {
    return ((isset($this->toolSettings->dozAutoLogin) && $this->toolSettings->dozAutoLogin) && in_array(KURZ_DOZENT, $this->allowedToolGroups));
  }

  private function isTeilnehmerAllowed(): bool
  {
    return ((isset($this->toolSettings->tnAutoLogin) && $this->toolSettings->tnAutoLogin) && in_array(KURZ_TEILNEHMER, $this->allowedToolGroups));
  }

  public function action()
  {
    $this->setzeMenupunkte();
    $benutzergruppe = $this->getBenutzergruppe();
    $checkEingaben = new HandleLoginAnfordernEingaben(
      $this->request->email,
      $this->request->passwort,
      $this->request->passwortWiederholt,
      $this->request->captchaOk,
      $this->request->geschlecht,
      $this->request->name,
      $this->request->vorname,
      $benutzergruppe,
      $this->toolSettings->dseZustimmung4Login,
      $this->request->dseZustimmung,
      $this->toolSettings->freiesPflichtfeldZustimmung4Login,
      $this->request->freiesPflichtfeldZustimmung
    );

    if ($this->request->isRefresh) {
      if (\SessionOperations::getVarValueWTIntern('AutoLoginErfolgreichAngefordert', false)) {
        $this->response->statusCodes[] = HandlePasswortAnfordernEingaben::ERROR_DOPPELT_ABSENDEN;
      } elseif (\SessionOperations::getVarValueWTIntern('NeuesLoginEmailErfolgreichVerschickt', false)) {
        $this->response->neuesLoginPerMail = true;
        $this->response->statusCodes[] = SendeLoginAnfordernUseCase::ERROR_DOPPELT_ABSENDEN;
      } elseif (\SessionOperations::getVarValueWTIntern('AutoLoginEinLoginExistiertBereits', false)) {
        $this->response->einLoginExistiertBereits = true;
        $this->response->statusCodes[] = HandlePasswortAnfordernEingaben::ERROR_DOPPELT_ABSENDEN;
      } else {
        $this->getFormValuesToResponse();
        $this->response->statusCodes = $checkEingaben->validateEingaben();
        $this->request->geschlecht = $checkEingaben->getGeschlecht();
      }
    } else {
      $statusCode = $checkEingaben->validateEingaben();
      if (empty($statusCode)) {
        $this->request->geschlecht = $checkEingaben->getGeschlecht();
        $this->response->statusCodes[] = $this->handleSendLoginAnforderung($benutzergruppe);
      } else {
        $this->response->statusCodes = $statusCode;
      }
      $this->getFormValuesToResponse();
    }

    $this->response->pwAnzahlZeichen = $this->toolSettings->pwdMinLength;
    $this->response->pwZahlErforderlich = $this->toolSettings->pwdNumbersRequired;
    $this->response->pwGrossKleinBuchstabenErforderlich = $this->toolSettings->pwdLowerUpperRequired;
    $this->response->pwSonderzeichenErforderlich = $this->toolSettings->pwdSpecialCharsRequired;

    $this->response->dozAutoLogin = $this->toolSettings->dozAutoLogin;
    $this->response->tnAutoLogin = $this->toolSettings->tnAutoLogin;

    $this->response->showDseZustimmung = $this->toolSettings->dseZustimmung4Login;
    $this->response->dseZustimmungLink = $this->toolSettings->dseZustimmungLink4Login;

    return $this->response;
  }

  private function getFormValuesToResponse(): void
  {
    $this->response->geschlecht = $this->request->geschlecht;
    $this->response->name = $this->request->name;
    $this->response->vorname = $this->request->vorname;
    $this->response->login = $this->request->email;
    $this->response->hinweis = isset($this->toolSettings->hint4Login) ? $this->toolSettings->hint4Login : null;
    $this->response->passwort = $this->request->passwort;
    $this->response->passwortWiederholt = $this->request->passwortWiederholt;
    if ($this->toolSettings->SSLLogin) {
      $this->response->https = \ConstantOperations::getHTTPSPath4Url(LOGIN);
    }
    $this->response->dseZustimmungChecked = $this->request->dseZustimmung ? \HTMLOperations::getEmptyAttribute('checked') : '';

    $benutzergruppe = $this->getBenutzergruppe();
    $this->response->benutzergruppeDozSelected = $benutzergruppe === self::DOZ_AUTO_LOGIN;
    $this->response->benutzergruppeTnSelected = $benutzergruppe === self::TN_AUTO_LOGIN;

    if ($this->toolSettings->freiesPflichtfeldZustimmung4Login) {
      $this->response->freiesPflichtfeld = true;
      $this->response->textFreiesPflichtfeld = $this->toolSettings->freiesPflichtfeldZustimmungText4Login;
    } else {
      $this->response->freiesPflichtfeld = false;
      $this->response->textFreiesPflichtfeld = '';
    }

    $this->response->freiesPflichtfeldChecked = $this->request->freiesPflichtfeldZustimmung ? \HTMLOperations::getEmptyAttribute('checked') : '';
  }

  private function handleSendOptInMail($requestObj): string
  {
    $pw = \PasswordFactory::getLatest();
    $passwordHashed = $pw->getHash($requestObj->passwort, array());
    $hashversion = $pw::getHashversion();
    $dblOptin = $this->getDblOption($requestObj, $passwordHashed, $hashversion);

    $benutzergruppe = $this->getBenutzergruppe();
    if ($benutzergruppe === self::TN_AUTO_LOGIN) {
      $dbwDoubleOptin = new \DBWorkDblOptinToolTnAutoLoginAnfordern(1, true);
    } else {
      $dbwDoubleOptin = new \DBWorkDblOptinToolDozAutoLoginAnfordern(1, true);
    } 
    $dblOptin->optin = $dbwDoubleOptin->saveDblOptin($dblOptin);

    $result = $this->sendOptInMail($dblOptin, $requestObj->email);

    if (!$result) {
      $dbwDoubleOptin->deleteByOptin($dblOptin->optin);

      return HandlePasswortAnfordernEingaben::ERROR_FEHLER_BEIM_DBLOPTIN_EMAIL_VERSAND;
    } else {
      return HandlePasswortAnfordernEingaben::SUCCESS_DBLOPTIN_EMAIL_VERSANDT;
    }
  }

  private function getDblOption($requestObj, $pPasswordHashed, $pHashversion): \WebDblOptin
  {
    $dtop = new \DateTimeOperations();
    $optin = new \WebDblOptin();
    $optin->bearbdatum = $dtop->getDateTimeNow();
    if (\StringOperations::strlen($optin->passworttext) == 0) {
      $optin->passworttext = $pPasswordHashed;
    }
    $optin->passwort = $pPasswordHashed;
    $optin->hashversion = $pHashversion;
    $optin->name = $requestObj->name;
    $optin->vorname = $requestObj->vorname;
    $optin->email = $requestObj->email;
    $optin->geschlecht = $requestObj->geschlecht;
    if ($this->toolSettings->dseZustimmung4Login) {
      $optin->dse_unterschrieben_datum = \DateTimeOperations::getDateTimeNow();
    }

    return $optin;
  }

  
  private function getLoginName(\WebDblOptin $pDbloptin): string
  {
    if (\DBWorkBASysSettings::isBremenLIS()) {
      $vornameName = \StringOperations::removeUmlaute(\StringOperations::substr($pDbloptin->vorname, 0, 1) . $pDbloptin->name);
      $dbwLogin = new \DBWorkLogin();
      $i = 0;
      do {
        $login = \StringOperations::strtoupper($vornameName) . ($i > 0 ? $i : '');
        $loginExists = $dbwLogin->loginExists($login);
        $i++;
      } while ($loginExists);
    } else {
      $login = $pDbloptin->email;
    }

    return $login;
  }

  private function sendOptInMail(\WebDblOptin $pDbloptin, string $pEmail): bool
  {
    if (!$pDbloptin->isEmpty()) {
      $allgeinstell = \AllgSettingsAPI::getAllgSettings();
      $viewModel = new SendeAutoLoginAnfordernEMailViewModel();
      $viewModel->vhsname = $allgeinstell->vhsname;
      $viewModel->name = $this->request->name;
      $viewModel->vorname = $this->request->vorname;
      $viewModel->login = $this->getLoginName($pDbloptin);
      $linkZuIndex = $this->getLinkZuIndex();
      $viewModel->linkDblOptIn = $linkZuIndex . '?action=confirmLogin&key=' . $pDbloptin->optin;

      $emailPresenter = new SendeAutoLoginAnfordernEMailPresenter($viewModel);
      $email = new \Kufer\Mail\EMail\EMailHTML($emailPresenter->getSubject(), $emailPresenter->getBody());
      $emailSender = \Kufer\Mail\Sender\EMailSenderFactory::create();
      $retour = $emailSender->sendFromEinrichtung(
        $email,
        array(new \Kufer\Mail\Address\EMailAddress($this->request->vorname . ' ' . $this->request->name, $pDbloptin->email)),
        'Sie'
      )->hasSentAnyMails();

      if (!$retour) {
        \Logger::logg('Tools Login anfordern DoubleOptin: Fehler beim Versenden der eMail an ' . $pEmail, 50);
      } else {
        \Logger::logg('Tools Login anfordern DoubleOptin: dbloptin mail sent', 1);
      }

      return $retour;
    } else {
      return false;
    }
  }

  private function getLinkZuIndex(): string
  {
    if ($this->toolSettings->SSLAnmeldung || $this->toolSettings->SSLLogin) {
      if ($this->toolSettings->SSLAnmeldung) {
        return \ConstantOperations::getHTTPSPath4Url('') . 'index.php';
      } else {
        return \ConstantOperations::getHTTPSPath4Url(LOGIN) . 'index.php';
      }
    } else {
      return 'http://' . \StringOperations::getCompleteUrlToSkript();
    }
  }

  private function setzeMenupunkte(): void
  {
    $menuBar = new \MenuBar();
    $menuBar->setMenuBarFromSettings(array(), 'LOGIN', null, true, true);
    $menuPunkte = $menuBar->getMenuPunkte();

    $zumLoginMenuPunkt = new \Kufer\Web\Classes\Menu\MenuPunkt\MenuPunkt4LoginSeite();
    array_unshift($menuPunkte, $zumLoginMenuPunkt);

    $this->response->menuPunkte = $menuPunkte;
  }

  private function getBenutzergruppe(): string
  {
    if ($this->isDozentAllowed()
      && $this->isTeilnehmerAllowed()) {
      return $this->request->benutzergruppe;
    }
    
    
    elseif ($this->isDozentAllowed()) {
      return static::DOZ_AUTO_LOGIN;
    } elseif ($this->isTeilnehmerAllowed()) {
      return static::TN_AUTO_LOGIN;
    }

    assert(false, 'Sollte nicht erreicht werden, da in hasAccess abgefangen');
  }

  private function isBenutzergruppeTn(string $pBenutzergruppe): bool
  {
    return $pBenutzergruppe === static::TN_AUTO_LOGIN;
  }

  private function isBenutzergruppeDoz(string $pBenutzergruppe): bool
  {
    return $pBenutzergruppe === static::DOZ_AUTO_LOGIN;
  }

  private function sollenNeuePersonenDirektAngelegtWerden(string $pBenutzergruppe): bool
  {
    return ($this->toolSettings->tnAutoLoginNeueTnDirektAnlegen && $this->isBenutzergruppeTn($pBenutzergruppe))
      || ($this->toolSettings->dozAutoLoginNeueDozDirektAnlegen && $this->isBenutzergruppeDoz($pBenutzergruppe));
  }

  private function getNameByUserGroup($pUserGroup, $pPlural = false): string
  {
    try {
      if ($pPlural) {
        return \ToolsAPI::getBezeichnungPluralForKurzBez($pUserGroup);
      } else {
        return \ToolsAPI::getBezeichnungSingularForKurzBez($pUserGroup);
      }
    } catch (\InvalidArgumentException $ex) {
      return ''; 
    }
  }

  private function getGruppenName(): string
  {
    switch($this->getBenutzergruppe()) {
      default:
        return '';
      case static::DOZ_AUTO_LOGIN:
        return KURZ_DOZENT;
      case static::TN_AUTO_LOGIN:
        return KURZ_TEILNEHMER;
    }
  }

  private function sendEmail(): string
  {
    $gruppenName = $this->getGruppenName();
    $emailBezeichnung = $this->getNameByUserGroup($gruppenName, true);

    $msg4UserGroup = (!trim($emailBezeichnung) == '') ? ' für das Tool für ' . $emailBezeichnung : '';

    $viewModel = new SendeLoginAnfordernEMailViewModel();
    $viewModel->geschlecht = $this->request->geschlecht;
    $viewModel->name = $this->request->name;
    $viewModel->vorname = $this->request->vorname;
    $viewModel->email = $this->request->email;
    
    $viewModel->dseZustimmung = $this->request->dseZustimmung;
    $viewModel->msg4UserGroup = $msg4UserGroup;

    $emailPresenter = new SendeLoginAnfordernEMailPresenter($viewModel);
    $email = new \Kufer\Mail\EMail\EMailHTML($emailPresenter->getSubject(), $emailPresenter->getBody());
    $email->addKuferToolsFooter('Neues Login anfordern');
    $emailSender = \Kufer\Mail\Sender\EMailSenderFactory::createForToolsWithCustomAddress($this->toolSettings->vhsEmailTool0Section5);

    if ($emailSender->informEinrichtung($email)->hasSentAnyMails()) {
      return SendeLoginAnfordernUseCase::SUCCESS_EMAIL_VERSANDT;
    } else {
      return SendeLoginAnfordernUseCase::ERROR_KEINE_EMAIL_VERSANDT;
    }
  }

  private function getPersonForCheckIsDublette(\Personn $pPerson): \Personn
  {
    $pPerson->name = $this->request->name;
    $pPerson->vorname = $this->request->vorname;
    $pPerson->setValue2Var('email', $this->request->email);

    return $pPerson;
  }

  private function handleSendLoginAnforderung(string $pBenutzergruppe): string
  {
    if ($this->sollenNeuePersonenDirektAngelegtWerden($pBenutzergruppe)) {
      $this->response->neuesLoginPerOptinMail = true;

      return $this->handleSendOptInMail($this->request);
    }

    if ($this->isBenutzergruppeTn($pBenutzergruppe)) {
      return $this->handleSendLoginAnforderungMitDublettenCheck(new \Teilnehmer());
    }

    if ($this->isBenutzergruppeDoz($pBenutzergruppe)) {
      return $this->handleSendLoginAnforderungMitDublettenCheck(new \Dozent());
    }

    return HandlePasswortAnfordernEingaben::ERROR_INTERNER_FEHLER;
  }

  private function handleSendLoginAnforderungMitDublettenCheck(\Personn $personEmptyObj): string
  {
    $person = $this->getPersonForCheckIsDublette($personEmptyObj);
    $personIdAry = $this->isPersonDublette($person);
    $isNeuePerson = empty($personIdAry['sqlid']) && empty($personIdAry['replikatid']);

    
    if ($isNeuePerson) {
      $this->response->neuesLoginPerMail = true;

      return $this->sendEmail();
    }

    
    $webUsers = $this->getWebUsers($personIdAry['replikatid'], $person->getDbTyp());
    if (count($webUsers) > 0) {
      $this->response->einLoginExistiertBereits = true;

      return HandlePasswortAnfordernEingaben::ERROR_EIN_LOGIN_EXISTIERT_BEREITS;
    }

    
    $this->response->neuesLoginPerOptinMail = true;

    return $this->handleSendOptInMail($this->request);
  }

  
  private function isPersonDublette(\Personn $pPerson)
  {
    if ($pPerson instanceof \Teilnehmer) {
      return \TeilnehmerAPI::isDublette($pPerson, \TeilnehmerAPI::ALGORITHM_DUBLETTE_SIMPEL_OHNE_STAMMHOERER);
    }
    if ($pPerson instanceof \Dozent) {
      return \DozentenAPI::isDublette($pPerson, \DozentenAPI::ALGORITHM_DUBLETTE_SIMPEL);
    }

    return array('sqlid' => false, 'replikatid' => false);
  }

  
  private function getWebUsers(int $pPersonReplikatId, string $pTyp): array
  {
    $dbwWebUser = new \DBWorkUser(1, true);

    return $dbwWebUser->getUsersByPersonNrAndTyp($pPersonReplikatId, $pTyp);
  }
}

class SendeAutoLoginAnfordernRequest
{
  public $geschlecht;
  public $name;
  public $vorname;
  public $email;
  public $passwort;
  public $passwortWiederholt;
  public $captchaOk;
  public $isRefresh;
  public $isXsrfOk;
  public $benutzergruppe;
  public $dseZustimmung;
  public $freiesPflichtfeldZustimmung;
}

class SendeAutoLoginAnfordernResponse extends \Kufer\Web\KuferTools\Basis\UseCase\BasisResponse
{
  public $menuPunkte;
  public $statusCodes = array();
  public $login;
  public $passwort;
  public $passwortWiederholt;
  public $https;
  public $geschlecht;
  public $name;
  public $vorname;
  public $email;
  public $hinweis;

  public $pwAnzahlZeichen;
  public $pwZahlErforderlich;
  public $pwGrossKleinBuchstabenErforderlich;
  public $pwSonderzeichenErforderlich;
  public $dozAutoLogin;
  public $tnAutoLogin;
  public $benutzergruppeDozSelected;
  public $benutzergruppeTnSelected;
  public $showDseZustimmung;
  public $dseZustimmungLink;
  public $dseZustimmungChecked;
  public $neuesLoginPerOptinMail = false;
  public $neuesLoginPerMail = false;
  public $einLoginExistiertBereits = false;
}