<?php

declare(strict_types=1);

namespace mirzaev\ebala\models;

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

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

// Библиотека для ArangoDB
use ArangoDBClient\Document as _document;

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

/**
 * Модель магазина
 *
 * @package mirzaev\ebala\models
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
final class market extends core
{
	use instance, status;

	/**
	 * Коллекция
	 *
	 * @todo Исправить "markets" на "market"
	 */
	final public const COLLECTION = 'market';

	/**
	 * Инстанция документа в базе данных
	 */
	protected readonly _document $document;

	/**
	 * Конструктор
	 *
	 * @param _document $instance Инстанция в базе данных
	 * @param array &$errors Реестр ошибок
	 *
	 * @return static Инстанция магазина
	 */
	public function __construct(_document $instance, array &$errors = [])
	{
		try {
			// Инициализация инстанции документа магазина в базе данных
			$this->document = $instance;
		} catch (exception $e) {
			// Запись в реестр ошибок
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}
	}

	/**
	 * Создать
	 *
	 * @param array $data Данные
	 * @param array &$errors Реестр ошибок
	 *
	 * @return string|null Идентификатор документа, если он был создан
	 */
	public static function create(array $data = [], array &$errors = []): ?string
	{
		try {
			if (collection::init(static::$arangodb->session, self::COLLECTION))
				if ($id = document::write(static::$arangodb->session, self::COLLECTION, $data + ['active' => true])) return $id;
				else throw new exception('Не удалось создать магазин');
			else throw new exception('Не удалось инициализировать коллекцию');
		} catch (exception $e) {
			// Запись в реестр ошибок
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		return null;
	}

	/**
	 * Найти связанный аккаунт
	 *
	 * @param string $_id Идентификатор магазина для которого будет искаться аккаунт
	 * @param array &$errors Реестр ошибок
	 *
	 * @return _document|array|null Массив инстанций документов в базе данных, если найдены
	 */
	public static function account(string $_id, array &$errors = []): _document|array|null
	{
		try {
			if (
				collection::init(static::$arangodb->session, static::COLLECTION)
				&& collection::init(static::$arangodb->session, account::COLLECTION)
				&& collection::init(static::$arangodb->session, account::COLLECTION . '_edge_market', true)
			) {
				// Инициализированы коллекции

				return collection::search(
					static::$arangodb->session,
					sprintf(
						<<<'AQL'
							FOR d IN %s
								LET e = (
									FOR e IN %s
										FILTER e._to == "%s"
										SORT e.created DESC
										LIMIT 1
										RETURN e
								)
								FILTER d._id == e[0]._from && d.active == true
								SORT d.created DESC
								LIMIT 1
								RETURN d
						AQL,
						account::COLLECTION,
						account::COLLECTION . '_edge_market',
						$_id
					)
				);
			} else throw new exception('Не удалось инициализировать коллекции');
		} catch (exception $e) {
			// Запись в реестр ошибок
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		return null;
	}

	/**
	 * Записать
	 *
	 * Записывает свойство в инстанцию документа аккаунта из базы данных
	 *
	 * @param string $name Название
	 * @param mixed $value Содержимое
	 *
	 * @return void
	 */
	public function __set(string $name, mixed $value = null): void
	{
		$this->document->{$name} = $value;
	}

	/**
	 * Прочитать
	 *
	 * Читает свойство из инстанции документа аккаунта из базы данных
	 *
	 * @param string $name Название
	 *
	 * @return mixed Данные свойства инстанции аккаунта или инстанции документа аккаунта из базы данных
	 */
	public function __get(string $name): mixed
	{
		return $this->document->{$name};
	}

	/**
	 * Проверить инициализированность
	 *
	 * Проверяет инициализированность свойства в инстанции документа аккаунта из базы данных
	 *
	 * @param string $name Название
	 *
	 * @return bool Свойство инициализировано?
	 */
	public function __isset(string $name): bool
	{
		return isset($this->document->{$name});
	}

	/**
	 * Удалить
	 *
	 * Деинициализировать свойство в инстанции документа аккаунта из базы данных
	 *
	 * @param string $name Название
	 *
	 * @return void
	 */
	public function __unset(string $name): void
	{
		unset($this->document->{$name});
	}

	/**
	 * Выполнить метод
	 *
	 * Выполнить метод в инстанции документа аккаунта из базы данных
	 *
	 * @param string $name Название
	 * @param array $arguments Аргументы
	 */
	public function __call(string $name, array $arguments = [])
	{
		if (method_exists($this->document, $name)) return $this->document->{$name}($arguments);
	}
}
