<?php

declare(strict_types=1);

namespace mirzaev\ebala\models;

// Project files
use mirzaev\ebala\models\traits\instance,
	mirzaev\ebala\models\traits\status,
	mirzaev\ebala\models\account,
	mirzaev\ebala\models\worker,
	mirzaev\ebala\models\market;

// Фреймворк ArangoDB
use mirzaev\arangodb\collection;

// Встроенные библиотеки
use exception;

/**
 * Модель реестра
 *
 * Генерирует HTML-документы из данных аккаунтов (accounts), магазинов (markets) и сотрудников (workers)
 *
 * @package mirzaev\ebala\models
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
final class registry extends core
{
	use instance, status;

	/**
	 * Generate workers list
	 *
	 * @param ?string $before Injection of AQL-code before search of edges
	 * @param ?string $after Injection of AQL-code after search of edges
	 * @param int $amount Amount of workers
	 * @param int $page Offset by amount
	 * @param string $target Collection or view name
	 * @param array $binds Binds for query
	 * @param array $errors Errors registry
	 *
	 * @return array Instances from ArangoDB
	 */
	public static function workers(
		?string $before = '',
		?string $after = '',
		int $amount = 100,
		int $page = 1,
		string $sort = 'account.created DESC, account._key DESC',
		string $target = account::COLLECTION,
		array $binds = [],
		array &$errors = []
	): array {
		try {
			if (collection::init(static::$arangodb->session, account::COLLECTION) && collection::init(static::$arangodb->session, worker::COLLECTION)) {
				// Инициализированы коллекции

				// Search the session data in ArangoDB
				$workers = collection::search(static::$arangodb->session, sprintf(
					<<<AQL
						FOR a IN %s
							%s
							LET b = (IS_SAME_COLLECTION('worker', a) 
								? (FOR _account IN INBOUND a._id account_edge_worker FILTER _account.deleted != true LIMIT 1 SORT _account.created DESC, _account._key DESC RETURN _account)[0]
								: (FOR _worker IN OUTBOUND a._id account_edge_worker FILTER _worker.deleted != true LIMIT 1 SORT _worker.created DESC, _worker._key DESC RETURN _worker)[0] 
							)
							FILTER b != null
							%s
							SORT %s
							LIMIT %d, %d
							RETURN {account, worker} 	
					AQL,
					$target,
					$before,
					$after,
					$sort,
					--$page <= 0 ? 0 : $amount * $page,
					$amount
				), $binds);

				// Exit (success)
				return empty($workers) ? [] : (is_array($workers) ? $workers : [$workers]);
			} else throw new exception('Не удалось инициализировать коллекции');
		} catch (exception $e) {
			// Write to the errors registry
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		// Exit (fail)
		return [];
	}

	/**
	 * Generate markets list
	 *
	 * @param ?string $before Injection of AQL-code before search of edges
	 * @param ?string $after Injection of AQL-code after search of edges
	 * @param int $amount Amount of markets
	 * @param int $page Offset by amount
	 * @param string $target Collection or view name
	 * @param array $binds Binds for query
	 * @param array $errors Errors registry
	 *
	 * @return array Instances from ArangoDB
	 */
	public static function markets(
		?string $before = '',
		?string $after = '',
		int $amount = 100,
		int $page = 1,
		string $sort = 'account.created DESC, account._key DESC',
		string $target = account::COLLECTION,
		array $binds = [],
		array &$errors = []
	): array {
		try {
			if (collection::init(static::$arangodb->session, account::COLLECTION) && collection::init(static::$arangodb->session, market::COLLECTION)) {
				// Инициализированы коллекции
				
				// Search the session data in ArangoDB
				$markets = collection::search(static::$arangodb->session, sprintf(
					<<<AQL
						FOR a IN %s
							%s
							LET b = (IS_SAME_COLLECTION('market', a) 
								? (FOR _account IN INBOUND a._id account_edge_market FILTER _account.deleted != true LIMIT 1 SORT _account.created DESC, _account._key DESC RETURN _account)[0]
								: (FOR _market IN OUTBOUND a._id account_edge_market FILTER _market.deleted != true LIMIT 1 SORT _market.created DESC, _market._key DESC RETURN _market)[0] 
							)
							FILTER b != null
							%s
							SORT %s
							LIMIT %d, %d
							RETURN {account, market} 					
					AQL,
					$target,
					$before,
					$after,
					$sort,
					--$page <= 0 ? 0 : $amount * $page,
					$amount
				), $binds);

				// Exit (success)
				return empty($markets) ? [] : (is_array($markets) ? $markets : [$markets]);
			} else throw new exception('Не удалось инициализировать коллекции');
		} catch (exception $e) {
			// Write to the errors registry
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		// Exit (fail)
		return [];
	}

	/**
	 * Generate operators list
	 *
	 * @param ?string $before Injection of AQL-code before search of edges
	 * @param int $amount Amount of operators
	 * @param int $page Offset by amount
	 * @param string $target Collection or view name
	 * @param array $binds Binds for query
	 * @param array $errors Errors registry
	 *
	 * @return array Instances from ArangoDB
	 */
	public static function operators(
		?string $before = '',
		int $amount = 100,
		int $page = 1,
		string $sort = 'account.created DESC, account._key DESC',
		string $target = account::COLLECTION,
		array $binds = [],
		array &$errors = []
	): array {
		try {
			if (collection::init(static::$arangodb->session, account::COLLECTION)) {
				// Инициализирована коллекция

				// Search the session data in ArangoDB
				$operators = collection::search(static::$arangodb->session, sprintf(
					<<<AQL
						FOR account IN %s
							%s
							SORT %s
							LIMIT %d, %d
							RETURN {account}					
					AQL,
					$target,
					$before,
					$sort,
					--$page <= 0 ? 0 : $amount * $page,
					$amount
				), $binds);

				// Exit (success)
				return empty($operators) ? [] : (is_array($operators) ? $operators : [$operators]);
			} else throw new exception('Не удалось инициализировать коллекции');
		} catch (exception $e) {
			// Write to the errors registry
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		// Exit (fail)
		return [];
	}

	/**
	 * Generate administrators list
	 *
	 * @param ?string $before Injection of AQL-code before search of edges
	 * @param int $amount Amount of administrators
	 * @param int $page Offset by amount
	 * @param string $target Collection or view name
	 * @param array $binds Binds for query
	 * @param array $errors Errors registry
	 *
	 * @return array Instances from ArangoDB
	 */
	public static function administrators(
		?string $before = '',
		int $amount = 100,
		int $page = 1,
		string $sort = 'account.created DESC, account._key DESC',
		string $target = account::COLLECTION,
		array $binds = [],
		array &$errors = []
	): array {
		try {
			if (collection::init(static::$arangodb->session, account::COLLECTION)) {
				// Инициализирована коллекция

				// Search the session data in ArangoDB
				$administrators = collection::search(static::$arangodb->session, sprintf(
					<<<AQL
						FOR account IN %s
							%s
							SORT %s
							LIMIT %d, %d
							RETURN {account}					
					AQL,
					$target,
					$before,
					$sort,
					--$page <= 0 ? 0 : $amount * $page,
					$amount
				), $binds);

				// Exit (success)
				return empty($administrators) ? [] : (is_array($administrators) ? $administrators : [$administrators]);
			} else throw new exception('Не удалось инициализировать коллекции');
		} catch (exception $e) {
			// Write to the errors registry
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
var_dump($errors);
		}

		// Exit (fail)
		return [];
	}
}
