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

namespace Kufer\Web\KuferTools\Dozent\HonorarAbnahme\HandleHonorarAbnahme\HonorarAbnahmeAblehnen;

use Kufer\Web\KuferTools\Basis\Presenter\HTMLEMailPresenter;
use Kufer\Web\Classes\Datamodul\HonorarAbnahme;
use Kufer\Web\Classes\Datamodul\HonorarAbnahmeDetail;
use Kufer\Web\Classes\Pdf\Convert\ConvertToPDF;
use Kufer\Web\KuferTools\Dozent\HonorarAbnahme\HandleHonorarAbnahme\HandleHonorarAbnahmeUseCase;
use Kufer\Web\Classes\Datamodul\HonorarAbnahmeBeleg;
use Kufer\Web\Classes\Datamodul\HonorarAbnahmeEintrag;
use Kufer\Web\Classes\Datamodul\HonorarAbnahmeReklamation;
use Kufer\Web\KuferTools\Utils\StatusMessages\PlainStatusMessage;
use Kufer\Web\KuferTools\Utils\StatusMessages\StatusMessage;
use Kufer\Web\KuferTools\Utils\StatusMessages\StatusMessageContainer;

class HonorarAbnahmeAblehnenUseCase extends HandleHonorarAbnahmeUseCase
{
  public function __construct($request)
  {
    parent::__construct($request, new HonorarAbnahmeAblehnenResponse());
  }

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

    $honorarAbnahme = $this->findHonorarAbnahme();
    if (is_null($honorarAbnahme)) {
      return false;
    }

    
    $honorarDetails = \ArrayOperations::setAttributAsKey(array_map(function(HonorarAbnahmeDetail $honorarAbnahmeDetail) {
      return $honorarAbnahmeDetail->honDetail;
    }, $honorarAbnahme->honorarAbnahmeDetails), 'id');
    
    $honorarDetailsForm = $this->request->honorarDetails;

    foreach ($honorarDetailsForm as $id => $obj) {
      if (!isset($honorarDetails[$id])) {
        return false;
      }

      if ($obj['art'] !== $honorarDetails[$id]->art) {
        return false;
      }
    }

    return true;
  }

  
  protected function handleHonorarAbnahme(): void
  {
    $this->honorarAbnahmeAblehnen();
  }

  
  private $cacheHonorarAbnahme;

  private function findHonorarAbnahme(): ?HonorarAbnahme
  {
    if (is_null($this->cacheHonorarAbnahme)) {
      try {
        $this->cacheHonorarAbnahme = \HonorarAbnahmeAPI::getHonorarAbnahmenById(
          $this->getUser()->getDnrIdentifier(),
          $this->request->id
        );
      } catch (\AbgleichApiException $ex) {
        \Logger::loggException($ex, 100);
        $this->response->error = true;

        return null;
      }
    }

    return $this->cacheHonorarAbnahme;
  }

  
  private function honorarAbnahmeAblehnen(): void
  {
    $this->response->honorarAbnahme = $this->findHonorarAbnahme();

    $checkFiles = $this->createCheckFiles();
    $uploadErrors = $checkFiles->checkMultipleFiles($this->request->uploadFiles);
    foreach ($uploadErrors as $uploadError) {
      if ($uploadError->status === \CheckFiles::UPLOAD_OK) {
        continue;
      }

      StatusMessageContainer::getSharedInstance()->addStatusMessageObj(PlainStatusMessage::getErrorMessageObj(
        strip_tags($uploadError->statusMessage)
      ));

      $this->response->error = true;
    }

    if ($this->response->error) {
      return;
    }

    $uploadedFiles = $this->uploadFiles($this->request->uploadFiles);
    if (is_null($uploadedFiles)) {
      $this->response->error = true;

      return;
    }

    
    list($honDetailsChanged, $honAbnahmeReklamationenNode) = $this->findChangedHonDetails();

    $dozNr = static::getUser()->getDnrIdentifier();
    $honAbnahmeEintrag = $this->getNewHonorarAbnahmeEintrag();
    $honAbnahmeEintragNode = \XMLNode::getXMLNode($honAbnahmeEintrag, 'honabnahme_eintrag');

    $honAbnahmeBelegeNode = new \XMLNode('honabnahme_belege');
    foreach ($uploadedFiles as $file) {
      $honAbnahmeBeleg = new HonorarAbnahmeBeleg();
      $honAbnahmeBeleg->dat_doc_id = $file;

      $honAbnahmeBelegeNode->addChild(\XMLNode::getXMLNode($honAbnahmeBeleg, 'honabnahme_beleg'));
    }

    $honAbnahmeAblehnenNode = new \XMLNode('honorarabnahme_ablehnen');
    $honAbnahmeAblehnenNode->addChild(new \XMLNode('dnr', $dozNr->getId()));
    $honAbnahmeAblehnenNode->addChild($honAbnahmeEintragNode);
    $honAbnahmeAblehnenNode->addChild($honAbnahmeReklamationenNode);
    $honAbnahmeAblehnenNode->addChild($honAbnahmeBelegeNode);

    $abgleichApi = new \AbgleichAPI();

    $abgleichApi->sendeNachricht(\AbgleichAPI::ABGLEICH_HONORAR_ABNAHME_ABLEHNEN, new \Nutzlast($honAbnahmeAblehnenNode));
  }

  private function createCheckFiles(): \CheckFiles
  {
    $toolAdmin = \ToolSettingsAPI::getToolSettings(0);

    if ($toolAdmin->convertUploadDocumentsToPDF) {
      return new \Kufer\Web\Classes\Fileupload\CheckFilesKuferToolsConvertToPDF();
    } else {
      return new \CheckFilesKuferTools();
    }
  }

  
  private function uploadFiles(array $uploadFiles): ?array
  {
    $toolSettingsAdmin = \ToolSettingsAPI::getToolSettings(0);

    try {
      $ids = array();
      foreach ($uploadFiles as $uploadFile) {
        $content = file_get_contents($uploadFile['tmp_name']);
        if ($toolSettingsAdmin->convertUploadDocumentsToPDF) {
          $newcontent = ConvertToPDF::create()->convert($content, $uploadFile['type']);
          if (is_null($newcontent)) {
            StatusMessageContainer::getSharedInstance()->addStatusMessageObj(
              new PlainStatusMessage(StatusMessage::MSG_BOX_ERROR, 'Die Datei enthält Fehler')
            );

            return null;
          } else {
            $content = $newcontent;
          }
        }

        $datDoc = $this->getDatDocObj($uploadFile);
        $ids[] = \DatDocAPI::sendAllgDokument2DMZRetuningIds(array($datDoc), $content)[0];

        @unlink($uploadFile['tmp_name']);
      }

      return $ids;
    } catch (\AbgleichApiException $ex) {
      \Logger::loggException($ex, 100);

      return null;
    }
  }

  protected function getDatDocObj(array $attachment)
  {
    $toolSettingsAdmin = \ToolSettingsAPI::getToolSettings(0);

    $user = $this->getUser();
    $datDoc = new \Dat_doc();
    $datDoc->datum = \DateTimeOperations::getDateNow();
    $datDoc->lfdnr = '';
    $datDoc->typ = 'D_D'; 
    $datDoc->knr = $this->findHonorarAbnahme()->getKurs()->id;
    $datDoc->nr = $user->getDnrIdentifier()->getId();

    $datDoc->pfaddok = '';
    $datDoc->pfadvorlage = $datDoc->pfaddok;
    $datDoc->datnamdok = $attachment['name'];
    if ($toolSettingsAdmin->convertUploadDocumentsToPDF) {
      $datDoc->datnamdok = preg_replace(':\\..*?$:', '.pdf', $datDoc->datnamdok);
    }
    $datDoc->datnamvorlage = '';
    $datDoc->name = $datDoc->datnamdok;
    $datDoc->versandtam = \DateTimeOperations::getDateTimeNow();

    $datDoc->beschreibung = $datDoc->datnamdok;

    $username = $user->getVarValue('name_vorname_ohne_komma');
    $datDoc->versandtvom = $username;
    $datDoc->info = 'Von ' . $username . ' hochgeladen bei Honorarabnahme';

    return $datDoc;
  }

  private function findChangedHonDetails()
  {
    $honorarAbnahme = $this->findHonorarAbnahme();
    
    $honDetails = \ArrayOperations::setAttributAsKey(array_map(static function(HonorarAbnahmeDetail $honorarAbnahmeDetail) {
      return $honorarAbnahmeDetail->honDetail;
    }, $honorarAbnahme->honorarAbnahmeDetails), 'id');
    
    $honDetailsChanged = array();

    $createChanged = function($key, $field, $value, $oldValue) {
      if (is_float($value)) {
        $value = \MathOperations::floatToString($value);
      }
      if (is_float($oldValue)) {
        $oldValue = \MathOperations::floatToString($oldValue);
      }

      $honAbnahmeReklamation = new HonorarAbnahmeReklamation();
      $honAbnahmeReklamation->hon_detail_id = $key;
      $honAbnahmeReklamation->field = $field;
      $honAbnahmeReklamation->value = $value;
      $honAbnahmeReklamation->old_value = $oldValue;

      return $honAbnahmeReklamation;
    };

    $honDetailToHonAbnahmeDetailIds = array();
    foreach ($honorarAbnahme->honorarAbnahmeDetails as $honorarAbnahmeDetail) {
      $honDetailToHonAbnahmeDetailIds[$honorarAbnahmeDetail->honDetail->id] = $honorarAbnahmeDetail->id;
    }

    $honorarDetailsForm = $this->request->honorarDetails;
    $honAbnahmeReklamationenNode = new \XMLNode('honabnahme_reklamationen');
    foreach ($honorarDetailsForm as $key => $formData) {
      $idHonAbnahmeDetail = $honDetailToHonAbnahmeDetailIds[$key] ?? null;
      if (is_null($idHonAbnahmeDetail)) {
        throw new \InvalidArgumentException("$key sollte als HonorarAbnahmeDetails existieren");
      }

      
      $honDetail = $honDetails[$key];
      $art = $formData['art'];
      if ($art === 'H') {
        $proue = $formData['proue'];
        $faktor = $formData['faktor'];

        if ($honDetail->faktor !== $faktor || $honDetail->satz !== $proue) {
          $honDetailChanged = clone $honDetail;
          $honDetailChanged->faktor = $faktor;
          $honDetailChanged->satz = $proue;
          $honDetailChanged->betrag = $faktor * $proue;

          $honDetailsChanged[$key] = $honDetailChanged;

          if ($honDetail->faktor !== $honDetailChanged->faktor) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'faktor', $honDetailChanged->faktor, $honDetail->faktor),
              'honabnahme_reklamation'
            ));
          }

          if ($honDetail->satz !== $honDetailChanged->satz) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'satz', $honDetailChanged->satz, $honDetail->satz),
              'honabnahme_reklamation'
            ));
          }

          if (false && $honDetail->betrag !== $honDetailChanged->betrag) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'betrag', $honDetailChanged->betrag, $honDetail->betrag),
              'honabnahme_reklamation'
            ));
          }

          unset($honDetailChanged);
        }

        unset($faktor, $proue);
      } elseif ($art === 'F') {
        $prokm = $formData['prokm'];
        $entfernung = $formData['entfernung'];
        $doppelt = $formData['doppelt'] ? 2 : 1;
        $faktor = $formData['faktor'];

        if (!in_array($honDetail->doppelt ?? 1, array(1, 2), true)) {
          $doppelt = $honDetail->doppelt;
        }

        if ($honDetail->satz !== $prokm
            || $honDetail->faktor !== $faktor
            || $honDetail->entfernung !== $entfernung
            || $honDetail->doppelt !== $doppelt) {
          $honDetailChanged = clone $honDetail;
          $honDetailChanged->satz = $prokm;
          $honDetailChanged->faktor = $faktor;
          $honDetailChanged->entfernung = $entfernung;
          $honDetailChanged->doppelt = $doppelt;
          $honDetailChanged->betrag = $prokm * $faktor * $entfernung * ($doppelt);

          $honDetailsChanged[$key] = $honDetailChanged;

          if ($honDetail->faktor !== $honDetailChanged->faktor) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'faktor', $honDetailChanged->faktor, $honDetail->faktor),
              'honabnahme_reklamation'
            ));
          }

          if ($honDetail->entfernung !== $honDetailChanged->entfernung) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'entfernung', $honDetailChanged->entfernung, $honDetail->entfernung),
              'honabnahme_reklamation'
            ));
          }

          if ($honDetail->satz !== $honDetailChanged->satz) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'satz', $honDetailChanged->satz, $honDetail->satz),
              'honabnahme_reklamation'
            ));
          }

          if ($honDetail->doppelt !== $honDetailChanged->doppelt) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'doppelt', $honDetailChanged->doppelt, $honDetail->doppelt),
              'honabnahme_reklamation'
            ));
          }

          if (false && $honDetail->betrag !== $honDetailChanged->betrag) {
            $honAbnahmeReklamationenNode->addChild(\XMLNode::getXMLNode(
              $createChanged($key, 'betrag', $honDetailChanged->betrag, $honDetail->betrag),
              'honabnahme_reklamation'
            ));
          }

          unset($honDetailChanged);
        }

        unset($prokm, $faktor, $entfernung);
      }

      unset($honDetail);
    }

    return array($honDetailsChanged, $honAbnahmeReklamationenNode);
  }

  protected function shouldSendEmail(): bool
  {
    return $this->toolSettings->emailBeiAblehnen;
  }

  protected function createEmail(): HTMLEMailPresenter
  {
    return new HonorarAbnahmeEMailAblehnenPresenter($this->response);
  }

  protected function getStatusAkzeptiertReklamiert(): int
  {
    return HonorarAbnahmeEintrag::STATUS_DOZENT_REKLAMIERT;
  }

  protected function getAkzeptiertReklamiertString(): string
  {
    return 'reklamiert';
  }

  protected function getAkzeptierenReklamierenString(): string
  {
    return 'Reklamieren';
  }
}