<?php declare(strict_types=0);
/*
** Copyright (C) 2001-2026 Zabbix SIA
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/


abstract class CControllerItem extends CController {

	protected function checkPermissions(): bool {
		if (!$this->hasInput('context')) {
			return false;
		}

		return $this->getInput('context') === 'host'
			? $this->checkAccess(CRoleHelper::UI_CONFIGURATION_HOSTS)
			: $this->checkAccess(CRoleHelper::UI_CONFIGURATION_TEMPLATES);
	}

	/**
	 * Common item field validation rules.
	 *
	 * @return array
	 */
	protected static function getValidationFields(): array {
		return [
			'name'					=> 'db items.name',
			'type'					=> 'in '.implode(',', array_keys(item_type2str())),
			'key'					=> 'db items.key_',
			'value_type'			=> 'in '.implode(',', [ITEM_VALUE_TYPE_UINT64, ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_STR, ITEM_VALUE_TYPE_LOG, ITEM_VALUE_TYPE_TEXT, ITEM_VALUE_TYPE_BINARY]),
			'url'					=> 'db items.url',
			'query_fields'			=> 'array',
			'parameters'			=> 'array',
			'script'				=> 'db items.params',
			'browser_script'		=> 'db items.params',
			'request_method'		=> 'in '.implode(',', [HTTPCHECK_REQUEST_GET, HTTPCHECK_REQUEST_POST, HTTPCHECK_REQUEST_PUT, HTTPCHECK_REQUEST_HEAD]),
			'custom_timeout'		=> 'in '.implode(',', [ZBX_ITEM_CUSTOM_TIMEOUT_DISABLED, ZBX_ITEM_CUSTOM_TIMEOUT_ENABLED]),
			'timeout'				=> 'db items.timeout',
			'post_type'				=> 'in '.implode(',', [ZBX_POSTTYPE_RAW, ZBX_POSTTYPE_JSON, ZBX_POSTTYPE_XML]),
			'posts'					=> 'db items.posts',
			'headers'				=> 'array',
			'status_codes'			=> 'db items.status_codes',
			'follow_redirects'		=> 'in '.implode(',', [HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF, HTTPTEST_STEP_FOLLOW_REDIRECTS_ON]),
			'retrieve_mode'			=> 'in '.implode(',', [HTTPTEST_STEP_RETRIEVE_MODE_CONTENT, HTTPTEST_STEP_RETRIEVE_MODE_HEADERS, HTTPTEST_STEP_RETRIEVE_MODE_BOTH]),
			'output_format'			=> 'in '.implode(',', [HTTPCHECK_STORE_RAW, HTTPCHECK_STORE_JSON]),
			'http_proxy'			=> 'db items.http_proxy',
			'http_authtype'			=> 'in '.implode(',', array_keys(httptest_authentications())),
			'http_username'			=> 'db items.username',
			'http_password'			=> 'db items.password',
			'verify_peer'			=> 'in '.implode(',', [ZBX_HTTP_VERIFY_PEER_OFF, ZBX_HTTP_VERIFY_PEER_ON]),
			'verify_host'			=> 'in '.implode(',', [ZBX_HTTP_VERIFY_HOST_OFF, ZBX_HTTP_VERIFY_HOST_ON]),
			'ssl_cert_file'			=> 'db items.ssl_cert_file',
			'ssl_key_file'			=> 'db items.ssl_key_file',
			'ssl_key_password'		=> 'db items.ssl_key_password',
			'master_itemid'			=> 'id',
			'interfaceid'			=> 'id',
			'snmp_oid'				=> 'db items.snmp_oid',
			'ipmi_sensor'			=> 'db items.ipmi_sensor',
			'authtype'				=> 'in '.implode(',', [ITEM_AUTHTYPE_PASSWORD, ITEM_AUTHTYPE_PUBLICKEY]),
			'jmx_endpoint'			=> 'db items.jmx_endpoint',
			'username'				=> 'db items.username',
			'publickey'				=> 'db items.publickey',
			'privatekey'			=> 'db items.privatekey',
			'passphrase'			=> 'db items.password',
			'password'				=> 'db items.password',
			'params_es'				=> 'db items.params',
			'params_ap'				=> 'db items.params',
			'params_f'				=> 'db items.params',
			'units'					=> 'db items.units',
			'delay'					=> 'db items.delay',
			'delay_flex'			=> 'array',
			'history_mode'			=> 'in '.implode(',', [ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]),
			'history'				=> 'db items.history',
			'trends_mode'			=> 'in '.implode(',', [ITEM_STORAGE_OFF, ITEM_STORAGE_CUSTOM]),
			'trends'				=> 'db items.trends',
			'logtimefmt'			=> 'db items.logtimefmt',
			'valuemapid'			=> 'id',
			'allow_traps'			=> 'in '.implode(',', [HTTPCHECK_ALLOW_TRAPS_OFF, HTTPCHECK_ALLOW_TRAPS_ON]),
			'trapper_hosts'			=> 'db items.trapper_hosts',
			'inventory_link'		=> 'db items.inventory_link',
			'description'			=> 'db items.description',
			'status'				=> 'in '.implode(',', [ITEM_STATUS_ACTIVE, ITEM_STATUS_DISABLED]),
			'tags'					=> 'array',
			'preprocessing'			=> 'array',
			'context'				=> 'required|in host,template',
			'hostid'				=> 'id',
			'itemid'				=> 'id',
			'templateid'			=> 'id'
		];
	}

	protected function validateInputExtended(): bool {
		if (!$this->validateInputPreprocessing($this->getInput('preprocessing', []))) {
			return false;
		}

		return true;
	}

	protected function validateInputPreprocessing(array $steps): bool {
		$has_delta_step = false;
		$has_any_error_step = false;
		$has_discard_value_step = false;
		$has_prometheus_step = false;

		foreach ($steps as $index => $step) {
			switch ($step['type']) {
				case ZBX_PREPROC_DELTA_SPEED:
				case ZBX_PREPROC_DELTA_VALUE:
					$has_delta_step && $this->addFormError("/preprocessing/$index/type",
						_('One "Change" step allowed per item.'), CFormValidator::ERROR_LEVEL_UNIQ
					);
					$has_delta_step = true;
					break;

				case ZBX_PREPROC_THROTTLE_VALUE:
				case ZBX_PREPROC_THROTTLE_TIMED_VALUE:
					$has_discard_value_step && $this->addFormError("/preprocessing/$index/type",
						_('One "Throttling" step allowed per item.'), CFormValidator::ERROR_LEVEL_UNIQ
					);
					$has_discard_value_step = true;
					break;

				case ZBX_PREPROC_PROMETHEUS_PATTERN:
				case ZBX_PREPROC_PROMETHEUS_TO_JSON:
					$has_prometheus_step && $this->addFormError("/preprocessing/$index/type",
						_('One "Prometheus" step allowed per item.'), CFormValidator::ERROR_LEVEL_UNIQ
					);
					$has_prometheus_step = true;
					break;

				case ZBX_PREPROC_VALIDATE_NOT_SUPPORTED:
					if ($step['params_0_not_supported'] == ZBX_PREPROC_MATCH_ERROR_ANY) {
						$has_any_error_step && $this->addFormError("/preprocessing/$index/type",
							_('Preprocessing step with such Name and Parameters combination already exists.'),
							CFormValidator::ERROR_LEVEL_UNIQ
						);
						$has_any_error_step = true;
					}
					break;

				case ZBX_PREPROC_VALIDATE_RANGE:
					$min = $step['params_0'];
					$max = $step['params_1'];

					if ($min !== '' && $max !== '') {
						$has_macro = substr($min, 0, 1) === '{' || substr($max, 0, 1) === '{';

						if (!$has_macro && floatval($min) >= floatval($max)) {
							$this->addFormError("/preprocessing/$index/params_1",
								_('Cannot be less than or equal to "Min".'), CFormValidator::ERROR_LEVEL_PRIMARY
							);
						}
					}
					break;
			}
		}

		return !$this->getValidationError();
	}

	/**
	 * Validate for referred objects exists and user have access.
	 *
	 * @return bool
	 */
	protected function validateReferredObjects(): bool {
		$ret = true;

		if ($this->hasInput('itemid')) {
			$ret = (bool) API::Item()->get([
				'output' => ['itemid'],
				'itemids' => [$this->getInput('itemid')],
				'editable' => true
			]);
		}

		if ($ret && $this->hasInput('hostid')) {
			if ($this->getInput('context') === 'host') {
				$ret = (bool) API::Host()->get([
					'output' => ['hostid'],
					'hostids' => [$this->getInput('hostid')]
				]);
			}
			else {
				$ret = (bool) API::Template()->get([
					'output' => ['templateid'],
					'templateids' => [$this->getInput('hostid')]
				]);
			}
		}

		if (!$ret) {
			error(_('No permissions to referred object or it does not exist!'));
		}

		return $ret;
	}

	/**
	 * Get form fields value normalized.
	 *
	 * @return array form fields data.
	 */
	protected function getFormValues(): array {
		$unchecked_values = [
			'allow_traps' => HTTPCHECK_ALLOW_TRAPS_OFF,
			'follow_redirects' => HTTPTEST_STEP_FOLLOW_REDIRECTS_OFF,
			'output_format' => HTTPCHECK_STORE_RAW,
			'status' => ITEM_STATUS_DISABLED,
			'verify_host' => ZBX_HTTP_VERIFY_HOST_OFF,
			'verify_peer' => ZBX_HTTP_VERIFY_PEER_OFF
		];
		$input = $unchecked_values + CItemHelper::getDefaults();
		$this->getInputs($input, array_keys($input));
		$input = CItemHelper::normalizeFormData($input);

		return $input;
	}
}
