<?php

namespace XcVm\Core\Http;

use XcVm\Core\Config\SettingsManager;

/**
 * ApiClient — internal API communication
 *
 * @package XC_VM_Core_Http
 * @author  Divarion_D <https://github.com/Divarion-D>
 * @copyright 2025-2026 Vateron Media
 * @link    https://github.com/Vateron-Media/XC_VM
 * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html
 */

class ApiClient {
	/**
	 * POST a request to the local admin API endpoint.
	 *
	 * @param array $rData    Request payload (api_pass is injected if configured).
	 * @param int   $rTimeout Connect/read timeout in seconds.
	 * @return string|bool Response body, or false on failure.
	 */
	public static function request($rData, $rTimeout = 5) {
		ini_set('default_socket_timeout', $rTimeout);
		$rAPI = 'http://127.0.0.1:' . intval(\XcVm\Domain\Server\ServerRepository::getAll()[SERVER_ID]['http_broadcast_port']) . '/admin/api';

		if (!empty(SettingsManager::getAll()['api_pass'])) {
			$rData['api_pass'] = SettingsManager::getAll()['api_pass'];
		}

		$rPost = http_build_query($rData);
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $rAPI);
		curl_setopt($ch, CURLOPT_POST, true);
		curl_setopt($ch, CURLOPT_POSTFIELDS, $rPost);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $rTimeout);
		curl_setopt($ch, CURLOPT_TIMEOUT, $rTimeout);

		return curl_exec($ch);
	}

	/**
	 * POST a request to a remote server's system API (when the server is online).
	 *
	 * @param int   $rServerID Target server id.
	 * @param array $rData     Request payload (live-streaming password injected).
	 * @param int   $rTimeout  Connect/read timeout in seconds.
	 * @return string|null Response body, or null if the server is offline/unknown.
	 */
	public static function systemRequest($rServerID, $rData, $rTimeout = 5) {
		ini_set('default_socket_timeout', $rTimeout);
		global $rServers, $rSettings;
		if (!is_array($rServers) || !isset($rServers[$rServerID])) {
			return null;
		}
		if ($rServers[$rServerID]['server_online']) {
			$rAPI = 'http://' . $rServers[intval($rServerID)]['server_ip'] . ':' . $rServers[intval($rServerID)]['http_broadcast_port'] . '/api';
			$rData['password'] = $rSettings['live_streaming_pass'];
			$rPost = http_build_query($rData);
			$ch = curl_init();
			curl_setopt($ch, CURLOPT_URL, $rAPI);
			curl_setopt($ch, CURLOPT_POST, true);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $rPost);
			curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
			curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $rTimeout);
			curl_setopt($ch, CURLOPT_TIMEOUT, $rTimeout);

			$rResult = curl_exec($ch);

			return $rResult;
		}
		return null;
	}

	/**
	 * Fire a request to several servers concurrently (fire-and-forget).
	 *
	 * @param int[] $rServerIDs Target server ids (offline servers are skipped).
	 * @param array $rData      Request payload sent to each server.
	 * @return array ['result' => true].
	 */
	public static function asyncRequest($rServerIDs, $rData) {
		$rURLs = array();
		global $rServers;

		foreach ($rServerIDs as $rServerID) {
			if (!$rServers[$rServerID]['server_online']) {
			} else {
				$rURLs[$rServerID] = array('url' => $rServers[$rServerID]['api_url'], 'postdata' => $rData);
			}
		}
		CurlClient::getMultiCURL($rURLs);

		return array('result' => true);
	}

	/**
	 * Recursively list a directory on a remote server via the system API.
	 *
	 * @param int           $rServerID Target server id.
	 * @param string        $rDirectory Directory to scan.
	 * @param string[]|null $rAllowed   Allowed file extensions filter.
	 * @return array|null Decoded directory listing, or null on failure.
	 */
	public static function scanRecursive($rServerID, $rDirectory, $rAllowed = null) {
		return json_decode(self::systemRequest($rServerID, array('action' => 'scandir_recursive', 'dir' => $rDirectory, 'allowed' => implode('|', $rAllowed))), true);
	}

	/**
	 * List a directory on a remote server via the system API.
	 *
	 * @param int           $rServerID  Target server id.
	 * @param string        $rDirectory Directory to scan.
	 * @param string[]|null $rAllowed   Allowed file extensions filter.
	 * @return array|null Decoded directory listing, or null on failure.
	 */
	public static function listDir($rServerID, $rDirectory, $rAllowed = null) {
		return json_decode(self::systemRequest($rServerID, array('action' => 'scandir', 'dir' => $rDirectory, 'allowed' => implode('|', $rAllowed))), true);
	}
}
