<?php declare(strict_types = 0);
/*
** Copyright (C) 2001-2025 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/>.
**/


namespace Widgets\Graph\Actions;

use API,
	CArrayHelper,
	CControllerDashboardWidgetView,
	CControllerResponseData,
	CGraphDraw,
	CMacrosResolverHelper,
	CRoleHelper,
	CUrl,
	CWebUser;

class WidgetView extends CControllerDashboardWidgetView {

	protected function init(): void {
		parent::init();

		$this->addValidationRules([
			'edit_mode' => 'in 0,1',
			'dashboardid' => 'db dashboard.dashboardid',
			'contents_width' => 'int32',
			'contents_height' => 'int32',
			'has_custom_time_period' => 'in 1'
		]);
	}

	protected function doAction(): void {
		$width = (int) $this->getInput('contents_width', 100);
		$height = (int) $this->getInput('contents_height', 100);

		$resourceid = null;
		$host = [];
		$graph = [];
		$profileIdx = 'web.dashboard.filter';
		$profileIdx2 = $this->getInput('dashboardid', 0);
		$is_resource_available = true;
		$header_name = $this->widget->getDefaultName();

		if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH && $this->fields_values['graphid']) {
			$resource_type = SCREEN_RESOURCE_GRAPH;
			$resourceid = reset($this->fields_values['graphid']);
			$graph_dims = getGraphDims($resourceid);
			$graph_dims['graphHeight'] = $height;
			$graph_dims['width'] = $width;
		}
		elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH
				&& $this->fields_values['itemid']) {

			$resource_type = SCREEN_RESOURCE_SIMPLE_GRAPH;
			$resourceid = $this->fields_values['itemid'][0];
			$graph_dims = getGraphDims();
			$graph_dims['graphHeight'] = $height;
			$graph_dims['width'] = $width;
		}
		else {
			$resource_type = null;
			$graph_dims = getGraphDims();
		}
		$graph_dims['shiftYtop'] = CGraphDraw::DEFAULT_TOP_BOTTOM_PADDING;

		$time_control_data = [
			'id' => '',
			'containerid' => '',
			'objDims' => $graph_dims,
			'loadSBox' => 0,
			'loadImage' => 1,
			'reloadOnAdd' => 1,
			'useCustomEvents' => 1
		];

		$flickerfreescreen_data = [
			'id' => '',
			'interval' => CWebUser::getRefresh(),
			'timeline' => [],
			'resourcetype' => $resource_type,
			'profileIdx' => $profileIdx,
			'profileIdx2' => $profileIdx2,
			'useCustomEvents' => 1
		];

		// Replace graph item by particular host item if the host has been overridden.
		if ($this->fields_values['override_hostid'] && $resourceid) {
			// Find same simple-graph item in the overridden host.
			if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) {
				$options = [
					'output' => ['itemid', 'name_resolved'],
					'selectHosts' => ['name'],
					'hostids' => $this->fields_values['override_hostid'],
					'filter' => [
						'value_type' => [ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_UINT64]
					],
					'webitems' => true
				];

				$src_items = [];

				if ($this->isTemplateDashboard()) {
					$options['itemids'] = $resourceid;
				}
				else {
					$src_items = API::Item()->get([
						'output' => ['key_'],
						'itemids' => $resourceid,
						'webitems' => true
					]);

					if ($src_items) {
						$options['filter']['key_'] = $src_items[0]['key_'];
					}
				}

				if ($this->isTemplateDashboard() || $src_items) {
					$items = API::Item()->get($options);
					$item = reset($items);

					if ($item) {
						$resourceid = $item['itemid'];
						$item = CArrayHelper::renameKeys($item, ['name_resolved' => 'name']);
					}
					else {
						$resourceid = null;
						$is_resource_available = false;
					}
				}
				else {
					$resourceid = null;
					$is_resource_available = false;
				}
			}
			// Find requested host and change graph details.
			elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) {
				// get host
				$hosts = API::Host()->get([
					'output' => ['hostid', 'host', 'name'],
					'hostids' => $this->fields_values['override_hostid']
				]);
				$host = reset($hosts);

				// get graph
				$graph = API::Graph()->get([
					'output' => API_OUTPUT_EXTEND,
					'selectGraphItems' => API_OUTPUT_EXTEND,
					'selectHosts' => [],
					'graphids' => $resourceid
				]);
				$graph = reset($graph);

				if ($graph && count($graph['hosts']) == 1) {
					$graph = $this->setAxisItem($graph, 'ymax');
					$graph = $this->setAxisItem($graph, 'ymin');
				}

				if ($graph) {
					$graph['hosts'] = $hosts;

					$items = $graph['gitems'];

					if (!$this->isTemplateDashboard()) {
						$items = getSameGraphItemsForHost($items, $this->fields_values['override_hostid'][0], false);
					}

					if ($items) {
						foreach ($items as &$item) {
							$item['host'] = $host['host'];
						}
						unset($item);

						$graph['name'] = CMacrosResolverHelper::resolveGraphName($graph['name'], $items);
					}
					else {
						$is_resource_available = false;
					}
				}
				else {
					$is_resource_available = false;
				}
			}
		}
		else {
			if (!$resourceid) {
				$is_resource_available = false;
			}
			elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) {
				$items = API::Item()->get([
					'output' => [!$this->isTemplateDashboard() ? 'name_resolved' : 'name', 'key_', 'delay', 'hostid'],
					'selectHosts' => ['name'],
					'itemids' => $resourceid,
					'filter' => ['value_type' => [ITEM_VALUE_TYPE_FLOAT, ITEM_VALUE_TYPE_UINT64]],
					'webitems' => true
				]);
				$item = reset($items);

				if (!$item) {
					$is_resource_available = false;
				}
				elseif (!$this->isTemplateDashboard()) {
					$item = CArrayHelper::renameKeys($item, ['name_resolved' => 'name']);
				}
			}
			elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) {
				// get graph, used below
				$graph = API::Graph()->get([
					'output' => API_OUTPUT_EXTEND,
					'selectHosts' => ['hostid', 'name'],
					'graphids' => $resourceid,
					'expandName' => true
				]);
				$graph = reset($graph);

				if (!$graph) {
					$is_resource_available = false;
				}
			}
		}

		if ($is_resource_available) {
			// Build graph action and data source links.
			if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_SIMPLE_GRAPH) {
				if ((!$this->isTemplateDashboard() || $this->fields_values['override_hostid'])
						&& !$this->hasInput('has_custom_time_period')) {
					$time_control_data['loadSBox'] = 1;
				}

				if ($resourceid) {
					$graph_src = (new CUrl('chart.php'))
						->setArgument('itemids', [$resourceid])
						->setArgument('width', $width)
						->setArgument('height', $height)
						->setArgument('legend', $this->fields_values['show_legend']);
				}
				else {
					$graph_src = new CUrl('chart3.php');
				}

				$graph_src
					->setArgument('from')
					->setArgument('to');

				$header_name = $this->isTemplateDashboard()
					? $item['name']
					: $item['hosts'][0]['name'].NAME_DELIMITER.$item['name'];
			}
			elseif ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) {
				$graph_src = '';

				$prepend_host_name = $this->isTemplateDashboard()
					? false
					: count($graph['hosts']) == 1 || $this->fields_values['override_hostid'];

				$header_name = $prepend_host_name
					? $graph['hosts'][0]['name'].NAME_DELIMITER.$graph['name']
					: $graph['name'];

				if ($this->fields_values['override_hostid'] && $resourceid
						&& array_key_exists('name', $host) && $graph) {
					$graph_src = $this->prepareGraphSrc($graph, $host);
				}

				if ($graph_dims['graphtype'] == GRAPH_TYPE_PIE || $graph_dims['graphtype'] == GRAPH_TYPE_EXPLODED) {
					if (!$this->fields_values['override_hostid'] || $graph_src === '') {
						$graph_src = (new CUrl('chart6.php'))
							->setArgument('graphid', $resourceid)
							->setArgument('graph3d', $graph['show_3d']);
					}
				}
				else {
					if (!$this->fields_values['override_hostid'] || $graph_src === '') {
						$graph_src = (new CUrl('chart2.php'))->setArgument('graphid', $resourceid);
					}

					if ((!$this->isTemplateDashboard() || $this->fields_values['override_hostid'])
							&& !$this->hasInput('has_custom_time_period')) {
						$time_control_data['loadSBox'] = 1;
					}
				}

				$graph_src
					->setArgument('width', $width)
					->setArgument('height', $height)
					->setArgument('legend', $this->fields_values['show_legend'] && $graph['show_legend'] ? 1 : 0)
					->setArgument('from')
					->setArgument('to');
			}

			if (!$this->isTemplateDashboard() || $this->fields_values['override_hostid']) {
				$graph_src->setArgument('resolve_macros', 1);
			}

			$graph_src
				->setArgument('profileIdx', $profileIdx)
				->setArgument('profileIdx2', $profileIdx2);

			if ($graph_dims['graphtype'] != GRAPH_TYPE_PIE && $graph_dims['graphtype'] != GRAPH_TYPE_EXPLODED) {
				$graph_src->setArgument('outer', '1');
			}

			$graph_src->setArgument('widget_view', '1');
			$time_control_data['src'] = $graph_src->getUrl();

			$graph_url = $this->prepareGraphUrl($graph, $resourceid);
		}

		$response = [
			'name' => $this->getInput('name', $header_name),
			'is_resource_available' => $is_resource_available,
			'widget' => [
				'graph_url' => ($is_resource_available && $graph_url !== null) ? $graph_url->getUrl() : null,
				'time_control_data' => $time_control_data,
				'flickerfreescreen_data' => $flickerfreescreen_data
			],
			'info' => $this->makeWidgetInfo(),
			'user' => [
				'debug_mode' => $this->getDebugMode()
			]
		];

		$this->setResponse(new CControllerResponseData($response));
	}

	/**
	 * Make widget specific info to show in widget's header.
	 */
	private function makeWidgetInfo(): array {
		$info = [];

		if ($this->hasInput('has_custom_time_period')) {
			$info[] = [
				'icon' => ZBX_ICON_TIME_PERIOD,
				'hint' => relativeDateToText($this->fields_values['time_period']['from'],
					$this->fields_values['time_period']['to']
				)
			];
		}

		return $info;
	}

	private function setAxisItem(array $graph, string $axis): array {
		$type_key = $axis.'_type';
		$itemid_key = $axis.'_itemid';

		if ($graph[$type_key] == GRAPH_YAXIS_TYPE_ITEM_VALUE && $graph[$itemid_key]) {
			$item = ['itemid' => $graph[$itemid_key]];

			if (!$this->isTemplateDashboard()) {
				$items = getSameGraphItemsForHost([$item],
					$this->fields_values['override_hostid'][0], false
				);
				$item = reset($items);
			}

			if ($item && $item['itemid'] > 0) {
				$graph[$itemid_key] = $item['itemid'];
			}
			else {
				$graph[$type_key] = GRAPH_YAXIS_TYPE_CALCULATED;
			}
		}

		return $graph;
	}

	private function prepareGraphSrc(array $graph, array $host): CUrl {
		if ($graph['graphtype'] == GRAPH_TYPE_PIE || $graph['graphtype'] == GRAPH_TYPE_EXPLODED) {
			$graph_src = (new CUrl('chart7.php'))
				->setArgument('name', $host['name'].NAME_DELIMITER.$graph['name'])
				->setArgument('graphtype', $graph['graphtype'])
				->setArgument('graph3d', $graph['show_3d']);
		}
		else {
			$graph_src = (new CUrl('chart3.php'))
				->setArgument('name', $host['name'].NAME_DELIMITER.$graph['name'])
				->setArgument('ymin_type', $graph['ymin_type'])
				->setArgument('ymax_type', $graph['ymax_type'])
				->setArgument('ymin_itemid', $graph['ymin_itemid'])
				->setArgument('ymax_itemid', $graph['ymax_itemid'])
				->setArgument('showworkperiod', $graph['show_work_period'])
				->setArgument('showtriggers', $graph['show_triggers'])
				->setArgument('graphtype', $graph['graphtype'])
				->setArgument('yaxismin', $graph['yaxismin'])
				->setArgument('yaxismax', $graph['yaxismax'])
				->setArgument('percent_left', $graph['percent_left'])
				->setArgument('percent_right', $graph['percent_right']);
		}

		$new_graph_items = getSameGraphItemsForHost($graph['gitems'],
			$this->fields_values['override_hostid'][0], false
		);

		foreach ($new_graph_items as &$new_graph_item) {
			unset($new_graph_item['gitemid'], $new_graph_item['graphid']);
		}
		unset($new_graph_item);

		$graph_src->setArgument('items', $new_graph_items);

		return $graph_src;
	}

	private function prepareGraphUrl(array $graph, ?string $resourceid = null): ?CUrl {
		if ($this->isEditMode() || !$graph
				|| ($this->isTemplateDashboard() && !$this->fields_values['override_hostid'])) {
			return null;
		}

		if ($this->fields_values['source_type'] == ZBX_WIDGET_FIELD_RESOURCE_GRAPH) {
			$has_host_graph = $this->fields_values['override_hostid']
				? (bool) API::Graph()->get([
					'output' => [],
					'hostids' => $this->fields_values['override_hostid'],
					'filter' => [
						'name' => $graph['name']
					]
				])
				: true;

			if ($has_host_graph && $this->checkAccess(CRoleHelper::UI_MONITORING_HOSTS)) {
				return (new CUrl('zabbix.php'))
					->setArgument('action', 'charts.view')
					->setArgument('filter_hostids', [$graph['hosts'][0]['hostid']])
					->setArgument('filter_name', $graph['name'])
					->setArgument('filter_show', GRAPH_FILTER_HOST)
					->setArgument('filter_set', '1')
					->setArgument('from')
					->setArgument('to');
			}
			else {
				return null;
			}
		}

		return $this->checkAccess(CRoleHelper::UI_MONITORING_LATEST_DATA)
			? (new CUrl('history.php'))
				->setArgument('itemids', [$resourceid])
				->setArgument('from')
				->setArgument('to')
			: null;
	}

	private function isEditMode(): bool {
		return (bool) $this->getInput('edit_mode', 0);
	}
}
