<?php

namespace Uhura\Grossmarkt\Backend\RecordList;

use TYPO3\CMS\Backend\RecordList\Event\ModifyRecordListTableActionsEvent;
use TYPO3\CMS\Backend\Utility\BackendUtility;
use TYPO3\CMS\Core\Database\Connection;
use TYPO3\CMS\Core\Imaging\Icon;
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use Uhura\Grossmarkt\Backend\Services\BackendUserAccess;

class DatabaseRecordList extends \TYPO3\CMS\Backend\RecordList\DatabaseRecordList
{
	public function getTable($table)
	{
		// Finding the total amount of records on the page
		$queryBuilderTotalItems = $this->getQueryBuilder($table, ['*'], false, 0, 1);

		// @todo Switch to `resetOrderBy()` as soon as the QueryBuilder facade has that method on board.
		$queryBuilderTotalItems->resetQueryPart('orderBy');
		$totalItems = (int)$queryBuilderTotalItems
			->count('*')
			->executeQuery()
			->fetchOne();
		if ($totalItems === 0) {
			return '';
		}
		// Setting the limits for the amount of records to be displayed in the list and single table view.
		// Using the default value and overwriting with page TSconfig and TCA config. The limit is forced
		// to be in the range of 0 - 10000.

		// default 100 for single table view
		$itemsLimitSingleTable = MathUtility::forceIntegerInRange((int)(
			$GLOBALS['TCA'][$table]['interface']['maxSingleDBListItems'] ??
			$this->modTSconfig['itemsLimitSingleTable'] ??
			100
		), 0, 10000);

		// default 20 for list view
		$itemsLimitPerTable = MathUtility::forceIntegerInRange((int)(
			$GLOBALS['TCA'][$table]['interface']['maxDBListItems'] ??
			$this->modTSconfig['itemsLimitPerTable'] ??
			20
		), 0, 10000);

		// Set limit depending on the view (single table vs. default)
		$itemsPerPage = $this->table ? $itemsLimitSingleTable : $itemsLimitPerTable;

		// Set limit defined by calling code
		if ($this->showLimit) {
			$itemsPerPage = $this->showLimit;
		}

		// Init
		$titleCol = $GLOBALS['TCA'][$table]['ctrl']['label'];
		$l10nEnabled = BackendUtility::isTableLocalizable($table);

		$this->fieldArray = $this->getColumnsToRender($table, true);
		// Creating the list of fields to include in the SQL query
		$selectFields = $this->getFieldsToSelect($table, $this->fieldArray);

		$firstElement = ($this->page - 1) * $itemsPerPage;
		if ($firstElement > 2 && $itemsPerPage > 0) {
			// Get the two previous rows for sorting if displaying page > 1
			$firstElement -= 2;
			$itemsPerPage += 2;
			$queryBuilder = $this->getQueryBuilder($table, $selectFields, true, $firstElement, $itemsPerPage);
			$firstElement += 2;
			$itemsPerPage -= 2;
		} else {
			$queryBuilder = $this->getQueryBuilder($table, $selectFields, true, $firstElement, $itemsPerPage);
		}
		if($table == 'tx_news_domain_model_news' && !$GLOBALS['BE_USER']->isAdmin()){
			$queryBuilder = $queryBuilder->andWhere(
				$queryBuilder->expr()->eq('owner', $queryBuilder->createNamedParameter((int)$GLOBALS['BE_USER']->user['uid'],Connection::PARAM_INT ))
			);
		}
		$queryResult = $queryBuilder->executeQuery();
		$columnsOutput = '';
		$onlyShowRecordsInSingleTableMode = $this->listOnlyInSingleTableMode && !$this->table;
		// Fetch records only if not in single table mode
		if ($onlyShowRecordsInSingleTableMode) {
			$dbCount = $totalItems;
		} elseif ($firstElement + $itemsPerPage <= $totalItems) {
			$dbCount = $itemsPerPage + 2;
		} else {
			$dbCount = $totalItems - $firstElement + 2;
		}
		// If any records was selected, render the list:
		if ($dbCount === 0) {
			return '';
		}

		// Get configuration of collapsed tables from user uc
		$lang = $this->getLanguageService();

		$tableIdentifier = $table;
		// Use a custom table title for translated pages
		if ($table === 'pages' && $this->showOnlyTranslatedRecords) {
			// pages records in list module are split into two own sections, one for pages with
			// sys_language_uid = 0 "Page" and an own section for sys_language_uid > 0 "Page Translation".
			// This if sets the different title for the page translation case and a unique table identifier
			// which is used in DOM as id.
			$tableTitle = htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:pageTranslation'));
			$tableIdentifier = 'pages_translated';
		} else {
			$tableTitle = htmlspecialchars($lang->sL($GLOBALS['TCA'][$table]['ctrl']['title']));
			if ($tableTitle === '') {
				$tableTitle = $table;
			}
		}

		$backendUser = $this->getBackendUserAuthentication();
		$tableCollapsed = (bool)($this->moduleData?->get('collapsedTables')[$tableIdentifier] ?? false);

		// Header line is drawn
		$theData = [];
		if ($this->disableSingleTableView) {
			$theData[$titleCol] = $tableTitle . ' (<span class="t3js-table-total-items">' . $totalItems . '</span>)';
		} else {
			$icon = $this->table // @todo separate table header from contract/expand link
				? $this->iconFactory
					->getIcon('actions-view-table-collapse', Icon::SIZE_SMALL)
					->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:contractView'))
					->render()
				: $this->iconFactory
					->getIcon('actions-view-table-expand', Icon::SIZE_SMALL)
					->setTitle($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:expandView'))
					->render();
			$theData[$titleCol] = $this->linkWrapTable($table, $tableTitle . ' (<span class="t3js-table-total-items">' . $totalItems . '</span>) ' . $icon);
		}
		$tableActions = '';
		$tableHeader = $theData[$titleCol];
		if (!$onlyShowRecordsInSingleTableMode) {
			// Add the "new record" button if user nave permissions
			if(isset($this->pageRow['uid']) && BackendUserAccess::isUserHaveCreateContentPermissions($this->pageRow['uid'], $table)){
				$tableActions .= $this->createActionButtonNewRecord($table) ?? '';
			}

			// Show the select box
			$tableActions .= $this->createActionButtonColumnSelector($table) ?? '';
			// Create the Download button
			$tableActions .= $this->createActionButtonDownload($table, $totalItems) ?? '';
			// Render collapse button if in multi table mode
			$tableActions .= $this->createActionButtonCollapse($table) ?? '';
		}
		$currentIdList = [];
		// Render table rows only if in multi table view or if in single table view
		$rowOutput = '';
		if (!$onlyShowRecordsInSingleTableMode || $this->table) {
			// Fixing an order table for sortby tables
			$this->currentTable = [];
			$allowManualSorting = ($GLOBALS['TCA'][$table]['ctrl']['sortby'] ?? false) && !$this->sortField;
			$prevUid = 0;
			$prevPrevUid = 0;
			// Get first two rows and initialize prevPrevUid and prevUid if on page > 1
			if ($firstElement > 2 && $itemsPerPage > 0) {
				$row = $queryResult->fetchAssociative();
				$prevPrevUid = -((int)$row['uid']);
				$row = $queryResult->fetchAssociative();
				$prevUid = $row['uid'];
			}
			$accRows = [];
			// Accumulate rows here
			while ($row = $queryResult->fetchAssociative()) {
				if (!$this->isRowListingConditionFulfilled($table, $row)) {
					continue;
				}
				// In offline workspace, look for alternative record
				BackendUtility::workspaceOL($table, $row, $backendUser->workspace, true);
				if (is_array($row)) {
					$accRows[] = $row;
					$currentIdList[] = $row['uid'];
					if ($allowManualSorting) {
						if ($prevUid) {
							$this->currentTable['prev'][$row['uid']] = $prevPrevUid;
							$this->currentTable['next'][$prevUid] = '-' . $row['uid'];
							$this->currentTable['prevUid'][$row['uid']] = $prevUid;
						}
						$prevPrevUid = isset($this->currentTable['prev'][$row['uid']]) ? -$prevUid : $row['pid'];
						$prevUid = $row['uid'];
					}
				}
			}
			// Render items:
			$this->CBnames = [];
			$this->duplicateStack = [];
			$cc = 0;

			// If no search happened it means that the selected
			// records are either default or All language and here we will not select translations
			// which point to the main record:
			$listTranslatedRecords = $l10nEnabled && $this->searchString === '' && !($this->hideTranslations === '*' || GeneralUtility::inList($this->hideTranslations, $table));
			foreach ($accRows as $row) {
				// Render item row if counter < limit
				if ($cc < $itemsPerPage) {
					$cc++;
					// Reset translations
					$translations = [];
					// Initialize with FALSE which causes the localization panel to not be displayed as
					// the record is already localized, in free mode or has sys_language_uid -1 set.
					// Only set to TRUE if TranslationConfigurationProvider::translationInfo() returns
					// an array indicating the record can be translated.
					$translationEnabled = false;
					// Guard clause so we can quickly return if a record is localized to "all languages"
					// It should only be possible to localize a record off default (uid 0)
					if ($l10nEnabled && ($row[$GLOBALS['TCA'][$table]['ctrl']['languageField'] ?? null] ?? false) !== -1) {
						$translationsRaw = $this->translateTools->translationInfo($table, $row['uid'], 0, $row, $selectFields);
						if (is_array($translationsRaw)) {
							$translationEnabled = true;
							$translations = $translationsRaw['translations'] ?? [];
						}
					}
					$rowOutput .= $this->renderListRow($table, $row, 0, $translations, $translationEnabled);
					if ($listTranslatedRecords) {
						foreach ($translations ?? [] as $lRow) {
							if (!$this->isRowListingConditionFulfilled($table, $lRow)) {
								continue;
							}
							// In offline workspace, look for alternative record:
							BackendUtility::workspaceOL($table, $lRow, $backendUser->workspace, true);
							if (is_array($lRow) && $backendUser->checkLanguageAccess($lRow[$GLOBALS['TCA'][$table]['ctrl']['languageField']])) {
								$currentIdList[] = $lRow['uid'];
								$rowOutput .= $this->renderListRow($table, $lRow, 1, [], false);
							}
						}
					}
				}
			}
			// Record navigation is added to the beginning and end of the table if in single table mode
			if ($this->table) {
				$pagination = $this->renderListNavigation($this->table, $totalItems, $itemsPerPage);
				$rowOutput = $pagination . $rowOutput . $pagination;
			} elseif ($totalItems > $itemsLimitPerTable) {
				// Show that there are more records than shown
				$rowOutput .= '
                    <tr data-multi-record-selection-element="true">
                        <td colspan="' . (count($this->fieldArray)) . '">
                            <a href="' . htmlspecialchars($this->listURL() . '&table=' . rawurlencode($tableIdentifier)) . '" class="btn btn-sm btn-default">
                                ' . $this->iconFactory->getIcon('actions-caret-down', Icon::SIZE_SMALL)->render() . '
                                ' . $this->getLanguageService()->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.expandTable') . '
                            </a>
                        </td>
                    </tr>';
			}
			// The header row for the table is now created
			$columnsOutput = $this->renderListHeader($table, $currentIdList);
		}

		// Initialize multi record selection actions
		$multiRecordSelectionActions = '';
		if ($this->noControlPanels === false) {
			$multiRecordSelectionActions = '
                <div class="recordlist-heading-row t3js-multi-record-selection-actions hidden">
                    <div class="recordlist-heading-title">
                        <strong>' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.selection')) . '</strong>
                    </div>
                    <div class="recordlist-heading-actions">
                        ' . $this->renderMultiRecordSelectionActions($table, $currentIdList) . '
                    </div>
                </div>
            ';
		}

		$recordListMessages = '';
		$recordlistMessageEntries = [];
		if ($backendUser->workspace > 0 && ExtensionManagementUtility::isLoaded('workspaces') && !BackendUtility::isTableWorkspaceEnabled($table)) {
			// In case the table is not editable in workspace inform the user about the missing actions
			if ($backendUser->workspaceAllowsLiveEditingInTable($table)) {
				$recordlistMessageEntries[] = [
					'message' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.editingLiveRecordsWarning'),
					'severity' => ContextualFeedbackSeverity::WARNING,
				];
			} else {
				$recordlistMessageEntries[] = [
					'message' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.notEditableInWorkspace'),
					'severity' => ContextualFeedbackSeverity::INFO,
				];
			}
		}

		foreach ($recordlistMessageEntries as $messageEntry) {
			$recordListMessages .= '<div class="alert alert-' . $messageEntry['severity']->getCssClass() . '">';
			$recordListMessages .= $this->iconFactory->getIcon($messageEntry['severity']->getIconIdentifier(), Icon::SIZE_SMALL)->render();
			$recordListMessages .= ' ';
			$recordListMessages .= htmlspecialchars($messageEntry['message'], ENT_QUOTES | ENT_HTML5);
			$recordListMessages .= '</div>';
		}

		$collapseClass = $tableCollapsed && !$this->table ? 'collapse' : 'collapse show';
		$dataState = $tableCollapsed && !$this->table ? 'collapsed' : 'expanded';
		return '
            <div class="recordlist" id="t3-table-' . htmlspecialchars($tableIdentifier) . '" data-multi-record-selection-identifier="t3-table-' . htmlspecialchars($tableIdentifier) . '">
                <form action="' . htmlspecialchars($this->listURL()) . '#t3-table-' . htmlspecialchars($tableIdentifier) . '" method="post" name="list-table-form-' . htmlspecialchars($tableIdentifier) . '">
                    <input type="hidden" name="cmd_table" value="' . htmlspecialchars($tableIdentifier) . '" />
                    <input type="hidden" name="cmd" />
                    <div class="recordlist-heading ' . ($multiRecordSelectionActions !== '' ? 'multi-record-selection-panel' : '') . '">
                        <div class="recordlist-heading-row">
                            <div class="recordlist-heading-title">' . $tableHeader . '</div>
                            <div class="recordlist-heading-actions">' . $tableActions . '</div>
                        </div>
                        ' . $multiRecordSelectionActions . '
                    </div>
                    ' . $recordListMessages . '
                    <div class="' . $collapseClass . '" data-state="' . $dataState . '" id="recordlist-' . htmlspecialchars($tableIdentifier) . '">
                        <div class="table-fit">
                            <table data-table="' . htmlspecialchars($tableIdentifier) . '" class="table table-striped table-hover">
                                <thead>
                                    ' . $columnsOutput . '
                                </thead>
                                <tbody data-multi-record-selection-row-selection="true">
                                    ' . $rowOutput . '
                                </tbody>
                            </table>
                        </div>
                    </div>
                </form>
            </div>
        ';
	}

	/**
	 * add action into correct section by user permissions
	 *
	 * @param array $cells
	 * @param string $action
	 * @param string $actionKey
	 */
	public function addActionToCellGroup(&$cells, $action, $actionKey)
	{
		if (
			isset($this->pageRow['uid']) &&
			($actionKey == 'delete'
			|| $actionKey == 'cut')
			&& !BackendUserAccess::isUserHaveDeleteContentPermissions($this->pageRow['uid'])){
			return;
		}
		if(
			isset($this->pageRow['uid']) &&
			(
				$actionKey == 'new'
				|| $actionKey == 'copy'
				|| $actionKey == 'moveUp'
				|| $actionKey == 'moveDown'
			)
			&& !BackendUserAccess::isUserHaveCreateContentPermissions($this->pageRow['uid']))
		{
			return;
		} else {
			$cellsMap = [
				'primary' => [
					'edit', 'hide', 'delete', 'moveUp', 'moveDown',
				],
				'secondary' => [
					'view', 'viewBig', 'history', 'stat', 'perms', 'new', 'move', 'moveLeft', 'moveRight', 'version', 'divider', 'copy', 'cut', 'pasteAfter', 'pasteInto',
				],
			];
			$classification = in_array($actionKey, $cellsMap['primary']) ? 'primary' : 'secondary';
			$cells[$classification][$actionKey] = $action;
			unset($cells[$actionKey]);
		}
	}

	/**
	 * @param string $table
	 * @param array $currentIdList
	 * @return string
	 */
	protected function renderMultiRecordSelectionActions(string $table, array $currentIdList): string
	{
		$actions = [];
		$lang = $this->getLanguageService();
		$userTsConfig = $this->getBackendUserAuthentication()->getTSConfig();
		$addClipboardActions = $this->showClipboardActions && $this->isClipboardFunctionalityEnabled($table);
		$editPermission = (
			($table === 'pages') ? $this->calcPerms->editPagePermissionIsGranted() : $this->calcPerms->editContentPermissionIsGranted()
			) && $this->overlayEditLockPermissions($table);

		// Add actions in case table can be modified by the current user
		if ($editPermission && $this->isEditable($table)) {
			$editActionConfiguration = GeneralUtility::jsonEncodeForHtmlAttribute([
				'idField' => 'uid',
				'tableName' => $table,
				'returnUrl' =>  $this->listURL(),
			], true);
			$actions['edit'] = '
                <button
                    type="button"
                    title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.edit')) . '"
                    class="btn btn-sm btn-default"
                    data-multi-record-selection-action="edit"
                    data-multi-record-selection-action-config="' . $editActionConfiguration . '"
                >
                    ' . $this->iconFactory->getIcon('actions-document-open', Icon::SIZE_SMALL)->render() . '
                    ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.edit')) . '
                </button>';

			if (!(bool)trim((string)($userTsConfig['options.']['disableDelete.'][$table] ?? $userTsConfig['options.']['disableDelete'] ?? ''))) {
				$deleteActionConfiguration = GeneralUtility::jsonEncodeForHtmlAttribute([
					'idField' => 'uid',
					'ok' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete'),
					'title' => $lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:clip_deleteMarked'),
					'content' => sprintf($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_mod_web_list.xlf:clip_deleteMarkedWarning'), $lang->sL($GLOBALS['TCA'][$table]['ctrl']['title'])),
				], true);
				$actions['delete'] = '
                    <button
                        type="button"
                        title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete')) . '"
                        class="btn btn-sm btn-default"
                        data-multi-record-selection-action="delete"
                        data-multi-record-selection-action-config="' . $deleteActionConfiguration . '"
                        aria-haspopup="dialog"
                    >
                        ' . $this->iconFactory->getIcon('actions-edit-delete', Icon::SIZE_SMALL)->render() . '
                        ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.delete')) . '
                    </button>';
			}
		}

		// Add clipboard actions in case they  are enabled and clipboard is not deactivated
		if ($addClipboardActions && (string)($this->modTSconfig['enableClipBoard'] ?? '') !== 'deactivated') {
			$copyMarked = '
                <button type="button"
                    class="btn btn-sm btn-default ' . ($this->clipObj->current === 'normal' ? 'disabled' : '') . '"
                    title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.transferToClipboard')) . '"
                    data-multi-record-selection-action="copyMarked"
                >
                    ' . $this->iconFactory->getIcon('actions-edit-copy', Icon::SIZE_SMALL)->render() . '
                    ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.transferToClipboard')) . '
                </button>';
			$removeMarked = '
                <button type="button"
                    class="btn btn-sm btn-default ' . ($this->clipObj->current === 'normal' ? 'disabled' : '') . '"
                    title="' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.removeFromClipboard')) . '"
                    data-multi-record-selection-action="removeMarked"
                >
                    ' . $this->iconFactory->getIcon('actions-minus', Icon::SIZE_SMALL)->render() . '
                    ' . htmlspecialchars($lang->sL('LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:cm.removeFromClipboard')) . '
                </button>';
			// Add "copy marked" after "edit", or in case "edit" is not set, as first item
			if (!isset($actions['edit'])) {
				$actions = array_merge(['copyMarked' => $copyMarked], $actions);
			} else {
				$end = array_splice($actions, (int)(array_search('edit', array_keys($actions), true)) + 1);
				$actions = array_merge($actions, ['copyMarked' => $copyMarked, 'removeMarked' => $removeMarked], $end);
			}
		}

		$event = $this->eventDispatcher->dispatch(
			new ModifyRecordListTableActionsEvent($actions, $table, $currentIdList, $this)
		);
		/** @var array<string, string> $actions */
		$actions = $event->getActions();

		if ($actions === []) {
			// In case the user does not have permissions to execute on of the above
			// actions or a hook removed all remaining actions, inform the user about this.
			return '
                <span class="badge badge-info">
                    ' . htmlspecialchars($lang->sL($event->getNoActionLabel() ?: 'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.noActionAvailable')) . '
                </span>
                ';
		}

		// Check user permissions for delete record
		if(isset($this->pageRow['uid']) && !BackendUserAccess::isUserHaveDeleteContentPermissions($this->pageRow['uid'])){
			unset($actions['delete']);
		}

		return implode(LF, $actions);
	}
}