<?php
/*
** 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/>.
**/

require_once 'vendor/autoload.php';

require_once dirname(__FILE__).'/CTest.php';

/**
 * Base class for Zabbix API tests.
 */
class CAPITest extends CTest {

	/**
	 * Check API response.
	 *
	 * @param array $response  response to be checked
	 * @param mixed $error     expected error:
	 *
	 * Possible $error types:
	 *     null/false - there should not be an error
	 *     array      - exact match
	 *     string     - error message should match
	 *     int        - error code should match
	 */
	public function checkResult($response, $error = null) {
		// Check response data.
		if ($error === null || $error === false) {
			$this->assertArrayHasKey('result', $response, json_encode($response, JSON_PRETTY_PRINT));
			$this->assertArrayNotHasKey('error', $response);
		}
		else {
			$this->assertArrayNotHasKey('result', $response);
			$this->assertArrayHasKey('error', $response);

			if (is_array($error)) {
				$this->assertSame($error, $response['error']);
			}
			elseif (is_string($error)) {
				$this->assertSame($error, $response['error']['data']);
			}
			elseif (is_numeric($error)) {
				$this->assertSame($error, $response['error']['code']);
			}
			elseif (is_callable($error)) {
				$this->assertSame($error(), $response['error']['data']);
			}
		}
	}

	/**
	 * Make API call.
	 *
	 * @param mixed  $data       String containing request data as json.
	 * @param string $sessionid  Authorization token.
	 *
	 * @return array
	 *
	 * @throws Exception      if API call fails.
	 */
	public function callRaw($data, ?string $sessionid = null) {
		return CAPIHelper::callRaw($data, $sessionid);
	}

	/**
	 * Prepare request for API call and make API call (@see callRaw).
	 *
	 * @param string $method    API method to be called.
	 * @param mixed $params     API call params.
	 * @param mixed $error      expected error if any or null/false if successful result is expected.
	 *
	 * @return array
	 */
	public function call($method, $params, $error = null) {
		if (CAPIHelper::getSessionId() === null) {
			$this->authorize(PHPUNIT_LOGIN_NAME, PHPUNIT_LOGIN_PWD);
		}

		$response = CAPIHelper::call($method, $params);
		$this->checkResult($response, $error);

		return $response;
	}

	/**
	 * Enable authorization/session for the following API calls.
	 */
	public static function enableAuthorization() {
		CAPIHelper::setSessionId(null);
	}

	/**
	 * Disable authorization/session for the following API calls.
	 */
	public static function disableAuthorization() {
		CAPIHelper::setSessionId(false);
	}

	/**
	 * Authorize as user.
	 *
	 * @param string $username
	 * @param string $password
	 */
	public function authorize(string $username, string $password) {
		CAPIHelper::authorize($username, $password);
	}

	/**
	 * @inheritdoc
	 */
	protected function onNotSuccessfulTest($t): void {
		if ($t instanceof Exception && CAPIHelper::getDebugInfo()) {
			CExceptionHelper::setMessage($t, $t->getMessage()."\n\nAPI calls:\n".CAPIHelper::getDebugInfoAsString());
		}

		parent::onNotSuccessfulTest($t);
	}

	/**
	 * Callback executed before every test case.
	 *
	 * @before
	 */
	public function onBeforeTestCase() {
		global $URL;
		$URL = PHPUNIT_URL.'api_jsonrpc.php';
		CAPIHelper::reset();

		parent::onBeforeTestCase();
	}

	/**
	 * Callback executed after every test case.
	 *
	 * @after
	 */
	public function onAfterTestCase() {
		parent::onAfterTestCase();

		CAPIHelper::clearDebugInfo();
	}
}