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

namespace Kufer\Web\KuferTools\Dozent\Anwesenheiten\Utils;

use Kufer\Web\Classes\Dbfilter\DozentenKurseSQLFilter;
use Kufer\Web\Classes\Stream\ArrayStream;
use Kufer\Web\KuferTools\Utils\DatamodulHelper\KursTage\DozentenKurstage;
use Kufer\Web\KuferTools\utils\dozent\KurstagRechnungsStatus;

class KurstageUtils
{
  
  public static function hasAccessToKurstag($pKurstagId, $pToolSettings)
  {
    $excludeKurstagStatus = 'A';
    $dbwKurstage = self::getDbwKursTage($pToolSettings, $excludeKurstagStatus);
    $datum = $dbwKurstage->getKurstag($pKurstagId)->datum;
    $maxDaysBack = $pToolSettings->aktKurstageBackScroll;
    $maxDaysBack4Leiter = $maxDaysBack;
    $dozentIsLeiter = self::isDozentLeiter($pToolSettings);
    if ($dozentIsLeiter) {
      $maxDaysBack4Leiter = max($pToolSettings->aktKurstageBackScroll4Leiter, $maxDaysBack);
    }

    if (self::istDatumMehrAlsXTageInVergangenheit($datum, $maxDaysBack4Leiter)) {
      return false;
    }

    if (!\DateTimeOperations::isDatebeforeNow($datum, -1)) {
      return false;
    }

    $data = self::getKurstageFromUebersicht($pToolSettings, $datum, $pKurstagId);

    if (empty($data)) {
      return false;
    }

    return true;
  }

  
  public static function hasAccessToAnwesenheitenOfKurstag(\Kurs $kurs, $kurstag, \ToolSettings $toolSettings): bool
  {
    $fachbereiche = array_filter(explode(':', $toolSettings->restrictKurstageForFachbereiche));

    if (in_array($kurs->fachb, $fachbereiche, true)) {
      switch ($toolSettings->restrictKurstageForFachbereicheZeitraum) {
        case 0:
          $today = \DateTimeOperations::getDateNow();
          $firstWeekday = \DateTimeOperations::getFirstDayOfWeek($today);
          $lastWeekday = \DateTimeOperations::getLastDayOfWeek($today);
          if (!\DateTimeOperations::isDateBetween($firstWeekday, $lastWeekday, $kurstag->datum)) {
            return false;
          }
          break;
        case 1:
          $today = \DateTimeOperations::getDateNow();
          $lastWeekday = \DateTimeOperations::getLastDayOfWeek($today);
          if (\DateTimeOperations::isDateAfter($kurstag->datum, $lastWeekday)) {
            return false;
          }
          break;
        case 2:
          $today = \DateTimeOperations::getDateNow();
          $firstWeekday = \DateTimeOperations::getFirstDayOfWeek($today);
          if (!\DateTimeOperations::isDateBefore($kurstag->datum, $firstWeekday)) {
            return false;
          }
          break;
        case 3:
          $today = \DateTimeOperations::getDateNow();
          $firstDay = \DateTimeOperations::addDays($today, -$toolSettings->restrictKurstageForFachbereicheZeitraumDays);
          $lastDay = \DateTimeOperations::addDays($today, $toolSettings->restrictKurstageForFachbereicheZeitraumDays);
          if (!\DateTimeOperations::isDateBetween($firstDay, $lastDay, $kurstag->datum)) {
            return false;
          }
          break;
      }
    }

    return true;
  }

  
  public static function istDatumMehrAlsXTageInVergangenheit($datum, $tage)
  {
    return \DateTimeOperations::isDatebeforeNow($datum, $tage);
  }

  public static function isDozentLeiter($pToolSettings)
  {
    static $result = null;
    if (is_null($result)) {
      if ($pToolSettings->showKurstage === 'leiter') {
        $user = self::getUser();
        $dbwKT = self::getDbwKursTage($pToolSettings);
        $maxDaysBack4Leiter = max($pToolSettings->aktKurstageBackScroll4Leiter, $pToolSettings->aktKurstageBackScroll);
        $maxDateBack4Leiter = \DateTimeOperations::getNextDate(\DateTimeOperations::getDateNow(), (-1 * $maxDaysBack4Leiter));
        
        $result = $dbwKT->isDozentLeiterFuerKTinZeitraum($user->dnr, $maxDateBack4Leiter, \DateTimeOperations::getDateNow());
      } else {
        $result = false;
      }
    }

    return $result;
  }

  
  public static function getKurstageFromUebersicht($pToolSettings, $pDatum, $pKurstagId = null)
  {
    $excludeKurstagStatus = 'A';

    $dbwHlGrundSys = \DBWorkHLGrundSys::getDefaultInstance(1, true);
    $anwKurstageX = $dbwHlGrundSys->getFeldWert('ANW_KURSTAGEX');
    if ($anwKurstageX === 'W') {
      $excludeKurstagStatus .= 'X';
    }

    $dbwKurstage = self::getDbwKursTage($pToolSettings, $excludeKurstagStatus);
    $user = self::getUser();
    if ($user->dnr > 0) {
      $dbwKurstage->toobject->nodoztool = true;
    }
    if ($user->tnr > 0) {
      $dbwKurstage->toobject->notntool = true;
    }
    $maxDaysBack = $pToolSettings->aktKurstageBackScroll;

    if (($pToolSettings->nurMitKursstatus ?? '') !== '') {
      $dbwKurstage->fromobject->kurs->realkursstatus = explode(',', $pToolSettings->nurMitKursstatus);
    }

    if (($pToolSettings->nurMitDozententyp ?? '') !== '') {
      $dbwKurstage->fromobject->kurs->kursDozententypen = explode(',', $pToolSettings->nurMitDozententyp);
    }

    if (self::isDozentLeiter($pToolSettings)) {
      
      
      
      $tagIstImNormalZeitraum = !self::istDatumMehrAlsXTageInVergangenheit($pDatum, $maxDaysBack);
      $kursTage = $dbwKurstage->getKurstagebyDozentNRAndDate4Leiter($user->dnr, $pDatum, !$tagIstImNormalZeitraum, $pKurstagId);
    } elseif ($pToolSettings->showKurstage === 'alle4kurs') {
      
      $kursTage = $dbwKurstage->getKurstage4DozentOfKursbyDateRange($user->dnr, $pDatum, $pDatum, $pKurstagId);
    } else { 
      
      $kursTage = $dbwKurstage->getKurstagebyDozentNRAndDateRange($user->id, $pDatum, $pDatum, $pKurstagId);
    }

    return $kursTage;
  }

  
  public static function getDbwKursTage($pToolSettings, $pExcludeKtStatus = '')
  {
    static $dbwKT = null;
    if (is_null($dbwKT)) {
      $ktStatusAndModifier = self::getKurstagStatusAndModifier($pToolSettings->ktstatus_ktuebersicht, $pExcludeKtStatus);
      $ktStatus = $ktStatusAndModifier['ktStatus'];
      $addKurstagWithSelectedStatus = $ktStatusAndModifier['modifier']; 
      $dbwKT = new \DBWorkKurseTageWT(1, false, $addKurstagWithSelectedStatus);
      $dbwKT->newSearch();
      $dbwKT->fromobject->ausfall = $ktStatus;
      $dbwKT->toobject->ausfall = $ktStatus;
      $dbwKT->orderby = $pToolSettings->sortkt_ktuebersicht;
      $dbwKT->orderbyasc = $pToolSettings->sortktasc_ktuebersicht;
    }

    return $dbwKT;
  }

  
  private static function getKurstagStatusAndModifier($pKtStatus, $pExcludeKtStatus)
  {
    $addKurstagWithSelectedStatus = true;
    if ($pExcludeKtStatus !== '') {
      if ($pKtStatus !== '') {
        for ($i = 0; $i < \StringOperations::strlen($pExcludeKtStatus); $i++) {
          $pKtStatus = str_replace($pExcludeKtStatus[$i], '', $pKtStatus);
        }
      } else {
        $pKtStatus = $pExcludeKtStatus;
        $addKurstagWithSelectedStatus = false;
      }
    }

    return array('ktStatus' => $pKtStatus, 'modifier' => $addKurstagWithSelectedStatus);
  }

  
  private static function getUser()
  {
    return \Kufer\Web\KuferTools\Basis\UseCase\ToolUseCase::getUser();
  }

  public static function canDozentKursAbschliessen(\ToolKurseDozentSettings $toolSettings, \Kurs $kurs): bool
  {
    if (empty($kurs->id)) { 
      return false;
    }

    $dbwKurstage = \DBWorkKurseTage::getDefaultInstance();

    if (\DBWorkBASysSettings::isNeussVhs()) {
      $kurstage = $dbwKurstage->getKurstageByKursIdAndStatus($kurs->id, \ConstantOperations::getKurstagStatusKuerzelHasTeilnahme());

      if (!static::hasFilledAllAnwesenheiten($kurs, $kurstage)) {
        return false;
      }

      $kurstage = \Kufer\Web\KuferTools\Utils\DatamodulHelper\KursTage\DozentenKurstage::erweitereKurstageUmRechnungsstatus(
        $kurstage,
        static::getUser(),
        DozentenKurstage::determineIfShouldCheckAnwesenheiten($toolSettings, $kurs)
      );

      return !empty(array_filter($kurstage, static function(\Kurstag $kurstag): bool {
        return $kurstag->rechnungStatus == KurstagRechnungsStatus::OFFEN;
      }));
    }

    $kurstage = $dbwKurstage->getKurstageIdsByKursIdAndStatus($kurs->id, \ConstantOperations::getKurstagStatusKuerzelHasTeilnahme());
    $dbwAnw = \DBWorkAnwesenheit::getDefaultInstance();
    foreach ($kurstage as $kurstag) {
      if (!$dbwAnw->hasKurstagAnwesenheiten($kurstag)) {
        return false;
      }
    }

    return true;
  }

  
  public static function hasFilledAllAnwesenheiten(\Kurs $kurs, array $kurstage, bool $kurstageOhneAnwErlaubt = true): bool
  {
    $belegungen = \DBWorkBelegung::getDefaultInstance()->getBelegungenbyKursNR($kurs->id, true);
    if (count($belegungen) === 0) {
      return true;
    }

    $anwesenheiten = \DBWorkAnwesenheit::getDefaultInstance()->getAnwesenheitenByBelegungenIdsUndKurstageIds(
      \ArrayOperations::mapAttribut($belegungen, 'id'),
      \ArrayOperations::mapAttribut($kurstage, 'id')
    );

    
    $anwesenheitenByKurstag = (new ArrayStream($anwesenheiten))
      ->groupBy(static function(\Anwesenheit $anw): int {
        return $anw->aktid;
      });

    
    $belegungenByKurstag = (new ArrayStream($belegungen))
      ->multiGroupBy(static function(\Belegung $belegung) use ($kurstage): iterable {
        return (new ArrayStream($kurstage))
          ->filter(static function(\Kurstag $kurstag) use ($belegung): bool {
            return $belegung->isBetweenEintrittAndAustritt($kurstag->datum);
          })
          ->map(static function(\Kurstag $kurstag): int {
            return $kurstag->id;
          })
          ->toIterator();
      });

    foreach ($kurstage as $kurstag) {
      $anwesenheitenAnzahl = count($anwesenheitenByKurstag[$kurstag->id] ?? array());
      $belegungGefiltertAnzahl = count($belegungenByKurstag[$kurstag->id] ?? array());
      if ($anwesenheitenAnzahl < $belegungGefiltertAnzahl) {
        return false;
      }
      if (!$kurstageOhneAnwErlaubt && $anwesenheitenAnzahl === 0) {
        return false;
      }
    }

    return true;
  }

  
  public static function areAllKurstageBefore(array $kurstage, string $date): bool
  {
    return !\ArrayOperations::any($kurstage, static function(\Kurstag $kurstag) use ($date) {
      return \DateTimeOperations::isEmptyOrDefault($kurstag->datum)
        || \DateTimeOperations::isDateAfter($kurstag->datum, $date);
    });
  }
}