<?php

namespace IMATHUZH\Qfq\Core\Form\FormElement;

use IMATHUZH\Qfq\Core\Database\DatabaseManager;
use IMATHUZH\Qfq\Core\Form\Form;
use IMATHUZH\Qfq\Core\Helper\HelperFile;
use IMATHUZH\Qfq\Core\Helper\HelperFormElement;
use IMATHUZH\Qfq\Core\Helper\KeyValueStringParser;
use IMATHUZH\Qfq\Core\Helper\OnArray;
use IMATHUZH\Qfq\Core\Helper\Path;
use IMATHUZH\Qfq\Core\Helper\Support;
use IMATHUZH\Qfq\Core\Report\Link;
use UserFormException;

class UploadFormElement extends AbstractFormElement {
    public string $uploadLink = '';
    public array $textDeleteCssClasses = array();
    private string $maxImageDimension;

    /**
     * @param $attributes
     * @param Form|null $form
     * @throws \CodeException
     * @throws \DbException
     * @throws \DownloadException
     * @throws \PhpOffice\PhpSpreadsheet\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Reader\Exception
     * @throws \PhpOffice\PhpSpreadsheet\Writer\Exception
     * @throws \Twig\Error\LoaderError
     * @throws \Twig\Error\RuntimeError
     * @throws \Twig\Error\SyntaxError
     * @throws \UserFormException
     * @throws \UserReportException
     */
    public function __construct($attributes, ?Form $form = null) {
        parent::__construct($attributes, $form);

        // Set defaults
        Support::setIfNotSet($this->attributes, FE_FILE_BUTTON_TEXT, FE_FILE_BUTTON_TEXT_DEFAULT);
        Support::setIfNotSet($this->attributes, FE_FILE_DOWNLOAD_BUTTON, '');
        Support::setIfNotSet($this->attributes, UPLOAD_TYPE, UPLOAD_TYPE_DEFAULT);

        $uploadType = $this->attributes[UPLOAD_TYPE];
        // Max Image Size FormElement -> Form -> System
        $this->maxImageDimension = $this->attributes[F_FE_MAX_IMAGE_DIMENSION];

        // Check for deprecated value of uploadType
        if ($uploadType === UPLOAD_TYPE_V1) {
            $this->attributes[UPLOAD_TYPE] = UPLOAD_TYPE_BUTTON;

            // Check for deprecated value of uploadType
        } else if ($uploadType === UPLOAD_TYPE_V2) {
            $this->attributes[UPLOAD_TYPE] = UPLOAD_TYPE_DND;

            // Invalid value of uploadType
        } else if (!in_array($uploadType, [UPLOAD_TYPE_BUTTON, UPLOAD_TYPE_DND, UPLOAD_MULTI_UPLOAD])) {
            $this->attributes[UPLOAD_TYPE] = UPLOAD_TYPE_DEFAULT;
        }

        $sipDownloadKey = 'sip-' . $this->attributes[FE_ID];
        $this->attributes[UPLOAD_SIP_DOWNLOAD_KEY] = $sipDownloadKey;

        $this->store->appendToStore(HelperFile::pathinfo($this->value), STORE_VAR);

        if (empty($this->attributes[FE_FILE_MIME_TYPE_ACCEPT])) {
            $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] = UPLOAD_DEFAULT_MIME_TYPE;
        }

        Support::setIfNotSet($this->attributes, FE_FILE_CAPTURE);
        if ($this->attributes[FE_FILE_CAPTURE] == FE_FILE_CAPTURE_CAMERA) {
            $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] = 'image/*';
        }

        if ($this->attributes[FE_FILE_MIME_TYPE_ACCEPT] == '*' || $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] == '*.*' || $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] == '*/*') {
            $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] = '';
        }

        # Build param array for uniq SIP
        $arr = array();
        $arr['fake_uniq_never_use_this'] = uniqid(); // make sure we get a new SIP. This is needed for multiple forms (same user) with r=0
        $arr[CLIENT_SIP_FOR_FORM] = $this->store->getVar(SIP_SIP, STORE_SIP);
        $arr[CLIENT_FE_NAME] = $this->attributes[FE_NAME];
        $arr[CLIENT_FORM] = $this->form->specFinal[F_NAME];
        $arr[CLIENT_RECORD_ID] = $this->store->getVar(SIP_RECORD_ID, STORE_SIP);
        $arr[CLIENT_PAGE_ID] = 'fake';
        $arr[EXISTING_PATH_FILE_NAME] = $this->value;
        $arr[FE_FILE_MIME_TYPE_ACCEPT] = $this->attributes[FE_FILE_MIME_TYPE_ACCEPT];
        $arr[UPLOAD_SIP_DOWNLOAD_KEY] = $sipDownloadKey;
        $arr[F_FE_MAX_IMAGE_DIMENSION] = $this->maxImageDimension;


        // Check Safari Bug #5578: in case Safari (Mac OS X or iOS) loads an 'upload element' with more than one file type, fall back to 'no preselection'.
        // Still do the file type check on the server side!
        if (strpos($this->attributes[FE_FILE_MIME_TYPE_ACCEPT], ',') !== false) {
            $ua = $this->store->getVar('HTTP_USER_AGENT', STORE_CLIENT, SANITIZE_ALLOW_ALNUMX);
            // Look for " Version/11.0 Mobile/15A5370a Safari/" or  " Version/9.0.2 Safari/"
            $rc = preg_match('; Version/.*Safari/;', $ua, $matches);
            // But not like " Version/4.0 Chrome/52.0.2743.98 Safari/"
            if ($rc == 1 && false === strpos($matches[0], ' Chrome/')) {
                $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] = ''; // This only fakes the upload dialog. But the server file type check is still active due to $arr[FE_FILE_MIME_TYPE_ACCEPT]
            }
        }

        $arr[FE_FILE_MAX_FILE_SIZE] = empty($this->attributes[FE_FILE_MAX_FILE_SIZE]) ? $this->form->specFinal[FE_FILE_MAX_FILE_SIZE] : $this->attributes[FE_FILE_MAX_FILE_SIZE];
        $maxFileSize = Support::returnBytes($arr[FE_FILE_MAX_FILE_SIZE]);
        if ((Support::returnBytes(ini_get('post_max_size')) < $maxFileSize) ||
            (Support::returnBytes(ini_get('upload_max_filesize')) < $maxFileSize)
        ) {
            throw new \UserFormException("Configured 'maxFileSize'=" . $arr[FE_FILE_MAX_FILE_SIZE] .
                " bigger than at least of one of the php.ini setttings 'post_max_size'=" . ini_get('post_max_size') .
                " or 'upload_max_filesize'=" . ini_get('upload_max_filesize'), ERROR_MAX_FILE_SIZE_TOO_BIG);
        }
        $arr[FE_FILE_MAX_FILE_SIZE] = $maxFileSize;
        $arr[F_UPLOAD_PDF_PROTECTED_ACTION] = $this->attributes[F_UPLOAD_PDF_PROTECTED_ACTION];

        $this->uploadLink = $this->sip->queryStringToSip(OnArray::toString($arr), RETURN_SIP);

        // Below, $value and $formElement[FE_MODE]=FE_MODE_REQUIRED will be changed. JSON will be made later, therefore we will need those values unchanged
        $jsonValue = $this->value;
        $jsonFormElement = $this->attributes;

        if ($this->value === '' || $this->value === false) {
            array_push($this->textDeleteCssClasses, 'hidden');
        } else {
            if ($this->attributes[FE_MODE] == FE_MODE_HIDDEN && $this->attributes[UPLOAD_TYPE] == UPLOAD_TYPE_V1) array_push($this->cssClasses, 'hidden');

            if ($this->attributes[FE_MODE] == FE_MODE_REQUIRED) {
                // #9347 Deactivated again since a value is always present in an Upload and if it is required then will always set it to mode SHOW and so remove the '*' in front of the Label.
//                $this->attributes[FE_MODE] = FE_MODE_SHOW; // #4495 - Upload, which already has been uploaded should not marked as required
                $this->htmlAttributes[DATA_REQUIRED] = FE_MODE_REQUIRED;
            }
        }

        if (!isset($this->attributes[F_UPLOAD_IDLE_TEXT])) {
            $this->attributes[F_UPLOAD_IDLE_TEXT] = $this->form->specFinal[F_UPLOAD_IDLE_TEXT];
        }
        if (!isset($this->attributes[F_UPLOAD_SUCCESS_MESSAGE])) {
            $this->attributes[F_UPLOAD_SUCCESS_MESSAGE] = $this->form->specFinal[F_UPLOAD_SUCCESS_MESSAGE];
        }

        // Filepond
        if ($this->attributes[UPLOAD_TYPE] == UPLOAD_TYPE_DND) {
            $this->handleFilepondUpload();
        } elseif ($this->attributes[UPLOAD_TYPE] == UPLOAD_MULTI_UPLOAD) {
            $this->handleUploadMulti($arr);
        } else {
            // Classic
            $this->handleClassicUpload();
        }
    }

    /**
     * Prepares this FE to be a Filepond upload element
     *
     * @return void
     * @throws \CodeException
     * @throws \DbException
     * @throws \IMATHUZH\Qfq\Core\Exception\RedirectResponse
     * @throws \UserFormException
     * @throws \UserReportException
     */
    private function handleFilepondUpload(): void {
        $defaultText = $this->attributes[F_UPLOAD_IDLE_TEXT];
        $projectPath = Path::absoluteApp();
        $this->attributes = HelperFormElement::prepareExtraButton($this->attributes, true);

        // Check for upload type new or old and initialize json config for new upload type
        $jsonConfig = array();
        $preloadedFiles = '';
        $downloadButton = $this->attributes[FE_FILE_DOWNLOAD_BUTTON] ?? '';
        $downloadButtonTokens = KeyValueStringParser::parse($downloadButton, PARAM_TOKEN_DELIMITER, PARAM_DELIMITER);

        $maxFileSizeInput = empty($this->attributes[FE_FILE_MAX_FILE_SIZE]) ? $this->form->specFinal[FE_FILE_MAX_FILE_SIZE] : $this->attributes[FE_FILE_MAX_FILE_SIZE];
        $maxFileSize = Support::returnBytes($maxFileSizeInput);

        $jsonConfig[UPLOAD_MIME_TYPE_ACCEPT] = $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] ?? null;
        $jsonConfig[UPLOAD_MAX_FILE_SIZE] = $maxFileSize ?? null;
        $jsonConfig[UPLOAD_MULTI_UPLOAD] = false;
        $jsonConfig[UPLOAD_DELETE_OPTION] = false;
        if (($this->attributes[FE_FILE_TRASH] ?? '1') === '1' && $this->attributes[FE_MODE] != FE_MODE_READONLY) {
            $jsonConfig[UPLOAD_DELETE_OPTION] = true;
        }
        $jsonConfig[UPLOAD_IMAGE_EDITOR] = false;
        $jsonConfig[UPLOAD_ALLOW] = true;
        $jsonConfig[UPLOAD_DOWNLOAD_ALLOW] = true;
        $jsonConfig[UPLOAD_TEXT] = $defaultText;
        $jsonConfig[UPLOAD_MAX_FILES] = null;
        $jsonConfig[UPLOAD_ID] = 1;
        $jsonConfig[UPLOAD_GROUP_ID] = $groupId ?? 0;
        $jsonConfig[UPLOAD_DROP_BACKGROUND] = 'white';
        $jsonConfig[UPLOAD_DOWNLOAD_BUTTON] = $this->evaluate->parse($downloadButtonTokens[TOKEN_TEXT] ?? '');
        $jsonConfig[UPLOAD_TOOL_TIP] = $this->evaluate->parse($downloadButtonTokens[TOKEN_TOOL_TIP] ?? '');
        $jsonConfig[UPLOAD_GLYPH_ICON] = $downloadButtonTokens[TOKEN_GLYPH] ?? '';
        $jsonConfig[UPLOAD_TYPE_FORM] = true;
        $jsonConfig[UPLOAD_FORM_ID] = $this->attributes[FE_HTML_ID];
        $jsonConfig[UPLOAD_SIP_DOWNLOAD_KEY] = $this->attributes[UPLOAD_SIP_DOWNLOAD_KEY];
        $jsonConfig[F_UPLOAD_SUCCESS_MESSAGE] = $this->attributes[F_UPLOAD_SUCCESS_MESSAGE];
        $jsonConfig[UPLOAD_EXTRA_BUTTON_HTML] = $this->attributes[FE_TMP_EXTRA_BUTTON_HTML];
        // Max image Dimensions
        [$jsonConfig[MAX_IMAGE_DIMENSION_WIDTH], $jsonConfig[MAX_IMAGE_DIMENSION_HEIGHT]] = OnArray::explodeDimension($this->maxImageDimension);

        if (!isset($jsonConfig[UPLOAD_PATH_FILE_NAME])) {
            $jsonConfig[UPLOAD_PATH_FILE_NAME] = '';
            $jsonConfig[UPLOAD_PATH_DEFAULT] = 1;
        }

        // Upload Note
        if (isset($this->attributes[FE_FILE_NOTE])) {
            // Add config
            $jsonConfig[FE_FILE_NOTE] = $this->attributes[FE_FILE_NOTE] === '' ? 'Upload Note' : $this->attributes[FE_FILE_NOTE];

            // Check if column exists
            $column = $this->attributes[FE_NAME];
            if ($this->store->getVar($column . FILE_NOTE_COLUMN_EXTENSION, STORE_TABLE_COLUMN_TYPES) !== false) {
                $jsonConfig[FE_FILE_NOTE_TEXT] = $this->store->getVar($column . FILE_NOTE_COLUMN_EXTENSION, STORE_BEFORE) ?? '';


            } elseif (isset($this->attributes[FE_SLAVE_ID])) {
                // Advanced Upload
                if (!isset($this->attributes[FE_FILE_NOTE_TARGET])) {
                    throw new UserFormException(FE_FILE_NOTE . " used in advanced upload requires " . FE_FILE_NOTE_TARGET . " parameter. " . FE_FILE_NOTE_TARGET . " = TABLE:COLUMN");
                }
                $advancedNote = explode(':', $this->attributes[FE_FILE_NOTE_TARGET]);
                $slaveId = $this->evaluate->parse($this->attributes[FE_SLAVE_ID]);
                $noteSql = "{{SELECT $advancedNote[1] FROM $advancedNote[0] WHERE id = " . $slaveId . "}}";
                $note = $this->evaluate->parse($noteSql);
                $jsonConfig[FE_FILE_NOTE_TEXT] = $note;
            } else {
                throw new UserFormException('Keyword `' . FE_FILE_NOTE . "` used but column `" . $column . FILE_NOTE_COLUMN_EXTENSION . "` missing.");
            }

            $name = explode('-', $this->htmlAttributes[HTML_ATTR_NAME]);
            $jsonConfig[FE_FILE_NOTE_INPUT_NAME] = $name[0] . FILE_NOTE_COLUMN_EXTENSION . '-' . $name[1];

        }

        $encodedJsonConfig = htmlspecialchars(json_encode($jsonConfig, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');
        $baseUrl = $this->store::getVar(SYSTEM_BASE_URL, STORE_SYSTEM);


        if ($this->value !== '') {
            $path = empty($this->value) || (!is_readable($this->value) && !empty($this->value)) ?  '' : $this->value;
            $pathToCheck = $projectPath . '/' . $path;

            if (is_readable($pathToCheck)) {

                // Currently no information except path is stored for upload over form.
                $preloadedFiles = '[{"id":"1","pathFileName":"' . $projectPath . '/' . $path . '","size":"null","type":"null"}]';
                $link = new Link($this->store->getSipInstance(), DatabaseManager::getInstance()->indexData);
                $sipDownload = $link->renderLink('', 's|M:file|d|r:8|F:' . $path);
                $this->store->setVar($this->attributes[UPLOAD_SIP_DOWNLOAD_KEY], array(), STORE_EXTRA);

                // Fill extra store for downloadable upload after save
                if ($this->store::getVar(API_SUBMIT_REASON, STORE_CLIENT . STORE_EMPTY, SANITIZE_ALLOW_ALNUMX) === API_SUBMIT_REASON_SAVE) {
                    $statusUpload[SIP_DOWNLOAD_PARAMETER] = 'F:' . $path;
                    $this->store->setVar($this->attributes[UPLOAD_SIP_DOWNLOAD_KEY], $statusUpload, STORE_EXTRA);
                }
            }
        }

        $encodedPreloadFilesConfig = htmlspecialchars($preloadedFiles, ENT_QUOTES, 'UTF-8');

        $apiUrls[FILE_ACTION_UPLOAD] = $baseUrl . 'typo3conf/ext/qfq/Classes/Api/file.php';
        $apiUrls[FILE_ACTION_DOWNLOAD] = $baseUrl . 'typo3conf/ext/qfq/Classes/Api/download.php';
        $encodedApiUrls = htmlspecialchars(json_encode($apiUrls, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        $uploadPdfAction = '&' . F_UPLOAD_PDF_PROTECTED_ACTION . '=' . $this->attributes[F_UPLOAD_PDF_PROTECTED_ACTION];
        $sipValues[FILE_ACTION_DOWNLOAD] = $sipDownload ?? '';
        $sipValues[FILE_ACTION_DELETE] = $this->uploadLink . '&action=delete';
        $sipValues[FILE_ACTION_UPLOAD] = $this->uploadLink . '&action=upload' . $uploadPdfAction;
        $encodedSipValues = htmlspecialchars(json_encode($sipValues, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        array_push($this->cssClasses, "fileupload", "single-upload", "form-upload");
        if (isset($this->attributes[FE_INPUT_EXTRA_BUTTON_LOCK])) {
            $this->cssClasses[] = 'qfq-disabled';
        }
        $this->htmlAttributes[UPLOAD_ATTR_TYPE] = UPLOAD_VALUE_FILE;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_PRELOADED_FILES] = $encodedPreloadFilesConfig;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_API_URLS] = $encodedApiUrls;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_SIPS] = $encodedSipValues;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_CONFIG] = $encodedJsonConfig;

        // Set FormStore value for dynamic update
        $uploadSip = $this->value;
        $uploaded = $this->store->getVar($uploadSip, STORE_EXTRA);
        if ($uploaded && !empty($uploaded[FILES_NAME]) && !empty($uploaded['tmp_name'])) {
            $this->store->setVar($this->attributes[FE_NAME], $uploaded[FILES_NAME], STORE_FORM, true);
        } elseif (!$uploaded) {
            $file = $this->store->getVar($this->attributes[FE_NAME], STORE_RECORD) ?? '';
            $this->store->setVar($this->attributes[FE_NAME], $file, STORE_FORM);
        } else {
            $this->store->setVar($this->attributes[FE_NAME], '0', STORE_FORM, true);
        }
    }

    /**
     * Prepares this FE to
     *
     * @return void
     * @throws \CodeException
     * @throws \DbException
     * @throws \IMATHUZH\Qfq\Core\Exception\RedirectResponse
     * @throws \UserFormException
     * @throws \UserReportException
     */
    private function handleClassicUpload(): void {

        $projectPath = Path::absoluteApp();

        $this->htmlAttributes[UPLOAD_ATTR_TYPE] = UPLOAD_VALUE_FILE;
        $this->htmlAttributes[UPLOAD_ATTR_TITLE] = $this->attributes[FE_TOOLTIP];
        $this->htmlAttributes[FE_FILE_CAPTURE] = $this->attributes[FE_FILE_CAPTURE];
        if (isset($this->attributes[FE_AUTOFOCUS])) $this->htmlAttributes[FE_AUTOFOCUS] = $this->attributes[FE_AUTOFOCUS];
        $this->htmlAttributes[FE_FILE_MIME_TYPE_ACCEPT] = $this->attributes[FE_FILE_MIME_TYPE_ACCEPT];
        if ($this->attributes[FE_DATA_LOAD] ?? '' === 'yes') $this->htmlAttributes[FE_DATA_LOAD] = FE_DATA_LOAD;
        $this->htmlAttributes[DATA_SIP] = $this->uploadLink;
        $this->htmlAttributes[ATTRIBUTE_DATA_REFERENCE] = $this->attributes[FE_DATA_REFERENCE];
        $this->htmlAttributes[UPLOAD_ATTR_STYLE] = 'display:none;';

        // Check if a custom text right beside the trash symbol is given.
        if (!empty($this->attributes[FE_FILE_TRASH_TEXT])) {
            $this->attributes[FE_FILE_TRASH_TEXT] = ' ' . $this->attributes[FE_FILE_TRASH_TEXT];
        }

        $value = $this->value;
        if (!empty($value)) {

            // Value is equal to pathFileName
            if (is_readable($value)) {
                $link = new Link($this->store->getSipInstance(), DatabaseManager::getInstance()->indexData);
                $value = $link->renderLink($this->evaluate->parse($this->attributes[FE_FILE_DOWNLOAD_BUTTON]), 's|M:file|d|F:' . $value);

                // Value is not empty and most likely equal to the sip of the file
                // Used for API calls
            } else if ($value !== '') {

                // CWD for API calls is /var/www/html/typo3conf/ext/qfq/Classes/Api
                // Existence and readability of file can only be checked with absolute path
                $pathToCheck = $projectPath . '/' . $this->attributes[FE_FILE_DESTINATION];

                // File exists and is readable
                if (is_readable($pathToCheck)) {
                    $link = new Link($this->store->getSipInstance(), DatabaseManager::getInstance()->indexData);
                    $value = $link->renderLink($this->evaluate->parse($this->attributes[FE_FILE_DOWNLOAD_BUTTON]), 's|M:file|d|G:glyphicon-file|F:' . $pathToCheck);
                    $this->attributes[FE_FILE_DOWNLOAD_BUTTON_HTML_INTERNAL] = $value;
                    $jsonFormElement[FE_FILE_DOWNLOAD_BUTTON_HTML_INTERNAL] = $value;
                }

                // Value is empty
            } else {
                $msg = "Already uploaded file not found.";
                // In case debugging is off: showing download button means 'never show the real pathfilename'
                if ($this->showDebugInfoFlag) {
                    $msg .= ' ShowDebugInfo=on >> Missing file is: ' . $value;
                }
                $value = $msg;
            }
            $this->value = $value;
        }
    }

    /**
     * Prepares this FE to be a Filepond upload element that supports multiUpload
     *
     * @throws \CodeException
     * @throws UserFormException
     * @throws \DbException
     * @throws \UserReportException
     */
    private function handleUploadMulti($arr): void {
        $table = $this->attributes[MULTI_UPLOAD_TARGET_TABLE] ?? MULTI_UPLOAD_TARGET_TABLE_DEFAULT;

        // Build Link that will be used for storing all information for the lifetime of the form.
        // This sip link will be used and changed throughout the whole process.
        $Link = $arr;

        // Remove variables that aren't needed for multi-upload.
        unset($Link[EXISTING_PATH_FILE_NAME], $Link[UPLOAD_SIP_DOWNLOAD_KEY]);

        // Initialize the uploads key to hold previous upload data.
        $Link[MULTI_UPLOAD_UPLOADS_KEY] = array();
        $previousUploadIndex = array();

        // Get the current uploadId, or use 0 if none exists.
        $uploadId = $this->attributes[UPLOAD_ID] ?? 0;

        // If there's a valid uploadId, fetch previous upload records from the database.
        if ($uploadId != 0) {
            $db = $this->databaseManager->getDataDb();
            $sql = "SELECT id, pathFileName AS full_path, fileSize, mimeType FROM $table WHERE uploadId = ?";
            $uploads = $db->sql($sql, ROW_REGULAR, [$uploadId]);

            foreach ($uploads as $index => $upload) {
                if (!is_readable($upload[MULTI_UPLOAD_FILE_FULL_PATH])) {
                    throw new UserFormException("Previously Uploaded files cant be read anymore");
                }
                $previousUploadIndex[] = $index . ':' . $upload[MULTI_UPLOAD_FILE_FULL_PATH] . ':' . $upload[COLUMN_FILE_SIZE] . ':' . $upload[COLUMN_MIME_TYPE];
                $uploads[$index][FILES_NAME] = basename($upload[MULTI_UPLOAD_FILE_FULL_PATH]);
            }
            // Store the JSON-encoded uploads array in the link.
            $Link[MULTI_UPLOAD_UPLOADS_KEY] = json_encode($uploads);
        }

        // Create sip
        $sipLink = $this->sip->queryStringToSip(OnArray::toString($Link), RETURN_SIP);
        $this->uploadLink = $sipLink;

        // Check for upload type and initialize json config for new upload type
        $jsonConfig = array();
        $downloadButton = $this->attributes[FE_FILE_DOWNLOAD_BUTTON] ?? '';
        $downloadButtonTokens = KeyValueStringParser::parse($downloadButton, PARAM_TOKEN_DELIMITER, PARAM_DELIMITER);

        $maxFileSizeInput = empty($this->attributes[FE_FILE_MAX_FILE_SIZE]) ? $this->form->specFinal[FE_FILE_MAX_FILE_SIZE] : $this->attributes[FE_FILE_MAX_FILE_SIZE];
        $maxFileSize = Support::returnBytes($maxFileSizeInput);

        // Set config for filepond
        $jsonConfig[UPLOAD_MIME_TYPE_ACCEPT] = $this->attributes[FE_FILE_MIME_TYPE_ACCEPT] ?? null;
        $jsonConfig[UPLOAD_MAX_FILE_SIZE] = $maxFileSize ?? null;
        $jsonConfig[UPLOAD_MULTI_UPLOAD] = true;
        $jsonConfig[UPLOAD_DELETE_OPTION] = false;
        if (($this->attributes[FE_FILE_TRASH] ?? '1') === '1' && $this->attributes[FE_MODE] != FE_MODE_READONLY) {
            $jsonConfig[UPLOAD_DELETE_OPTION] = true;
        }
        $jsonConfig[UPLOAD_IMAGE_EDITOR] = false;
        $jsonConfig[UPLOAD_ALLOW] = true;
        $jsonConfig[UPLOAD_DOWNLOAD_ALLOW] = true;
        $jsonConfig[UPLOAD_TEXT] = $this->attributes[F_UPLOAD_IDLE_TEXT];
        $jsonConfig[UPLOAD_MAX_FILES] = $this->attributes[UPLOAD_MAX_FILES] ?? null;
        $jsonConfig[UPLOAD_GROUP_ID] = $uploadId;
        $jsonConfig[UPLOAD_DROP_BACKGROUND] = 'white';
        $jsonConfig[UPLOAD_DOWNLOAD_BUTTON] = $this->evaluate->parse($downloadButtonTokens[TOKEN_TEXT] ?? '');
        $jsonConfig[UPLOAD_TOOL_TIP] = $this->evaluate->parse($downloadButtonTokens[TOKEN_TOOL_TIP] ?? '');
        $jsonConfig[UPLOAD_GLYPH_ICON] = $downloadButtonTokens[TOKEN_GLYPH] ?? '';
        $jsonConfig[UPLOAD_TYPE_FORM] = true;
        $jsonConfig[UPLOAD_FORM_ID] = $this->attributes[FE_HTML_ID];
        $jsonConfig[F_UPLOAD_SUCCESS_MESSAGE] = $this->attributes[F_UPLOAD_SUCCESS_MESSAGE];
        // Max image Dimensions
        [$jsonConfig[MAX_IMAGE_DIMENSION_WIDTH], $jsonConfig[MAX_IMAGE_DIMENSION_HEIGHT]] = OnArray::explodeDimension($this->maxImageDimension);

        if (isset($this->attributes[FE_FILE_NOTE])) {
            throw new UserFormException(FE_FILE_NOTE . " is not implemented for FE multiUpload");
        }

        $encodedJsonConfig = htmlspecialchars(json_encode($jsonConfig, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        // Set up API URLs for file upload and download.
        $baseUrl = $this->store::getVar(SYSTEM_BASE_URL, STORE_SYSTEM);
        $apiUrls[FILE_ACTION_UPLOAD] = $baseUrl . 'typo3conf/ext/qfq/Classes/Api/file.php';
        $apiUrls[FILE_ACTION_DOWNLOAD] = $baseUrl . 'typo3conf/ext/qfq/Classes/Api/download.php';
        $encodedApiUrls = htmlspecialchars(json_encode($apiUrls, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        // Build SIP values for download, delete, and upload actions.
        $uploadPdfAction = '&' . F_UPLOAD_PDF_PROTECTED_ACTION . '=' . $this->attributes[F_UPLOAD_PDF_PROTECTED_ACTION];
        $sipValues[FILE_ACTION_DOWNLOAD] = $sipLink . '&mode=' . MULTI_UPLOAD_API_MODE_DOWNLOAD;
        $sipValues[FILE_ACTION_DELETE] = $sipLink . '&action=' . MULTI_UPLOAD_API_ACTION_DELETE;
        $sipValues[FILE_ACTION_UPLOAD] = $sipLink . '&action=' . MULTI_UPLOAD_API_ACTION_UPLOAD . $uploadPdfAction;
        $encodedSipValues = htmlspecialchars(json_encode($sipValues, JSON_UNESCAPED_SLASHES), ENT_QUOTES, 'UTF-8');

        array_push($this->cssClasses, "file-uploadMulti", "form-upload");
        $this->htmlAttributes[UPLOAD_ATTR_TYPE] = UPLOAD_VALUE_FILE;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_PRELOADED_FILES] = $previousUploadIndex;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_API_URLS] = $encodedApiUrls;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_SIPS] = $encodedSipValues;
        $this->htmlAttributes[UPLOAD_ATTR_DATA_CONFIG] = $encodedJsonConfig;
    }
}