<?php

declare(strict_types=1);

namespace mirzaev\huesos\models\traits;

// Files of the project
use mirzaev\huesos\models\interfaces\collection as collection_interface,
	mirzaev\huesos\models\interfaces\document as document_interface,
	mirzaev\huesos\models\traits\document as document_trait,
	mirzaev\huesos\models\connect,
	mirzaev\huesos\models\cart as model;

// Library для ArangoDB
use ArangoDBClient\Document as _document;

// Framework for ArangoDB
use mirzaev\arangodb\collection,
	mirzaev\arangodb\document;

// Built-in libraries
use exception;

/**
 * Cart
 *
 * Cart for a document from ArangoDB
 *
 * @uses collection_interface
 * @uses document_interface
 * @package mirzaev\huesos\models\traits
 *
 * @license http://www.wtfpl.net/ Do What The Fuck You Want To Public License
 * @author Arsen Mirzaev Tatyano-Muradovich <arsen@mirzaev.sexy>
 */
trait cart
{
	use document_trait;

	/**
	 * Cart
	 *
	 * Search for a connected cart
	 *
	 * @param array &$errors Registry of errors
	 *
	 * @return model|null An object implements the instance of the cart document from ArangoDB, if found
	 */
	public function initialize(array &$errors = []): ?model
	{
		try {
			if (collection::initialize(static::COLLECTION, static::TYPE, errors: $errors)) {
				if (collection::initialize(connect::COLLECTION, connect::TYPE, errors: $errors)) {
					if (collection::initialize(model::COLLECTION, model::TYPE, errors: $errors)) {
						// Initialized collections

						// Search for connected cart
						$result = collection::execute(
							<<<AQL
							FOR v IN 1..1 INBOUND @document GRAPH @graph
								FILTER IS_SAME_COLLECTION(@cart, v._id) && v.active == true && v.ordered != true
								SORT v.updated DESC, v.created DESC
								LIMIT 1
								RETURN v  
							AQL,
							[
								'cart' => model::COLLECTION,
								'graph' => 'users',
								'document' => $this->document->getId()
							],
							errors: $errors
						);

						if ($result instanceof _document) {
							// Found the cart

							// Initializing the object
							$cart = new model;

							if (method_exists($cart, '__document')) {
								// Object can implement a document from ArangoDB

								// Writing the instance of cart document from ArangoDB to the implement object
								$cart->__document($result);

								// Exit (success)
								return $cart;
							}
						} else {
							// Not found the cart

							// Initializing a new cart and write they into ArangoDB
							$_id = document::write(
								model::COLLECTION,
								[
									'active' => true,
								]
							);

							if ($result = collection::execute(
								<<<'AQL'
								FOR d IN @@collection
									FILTER d._id == @_id && d.active == true
									RETURN d
								AQL,
								[
									'@collection' => model::COLLECTION,
									'_id' => $_id
								],
								errors: $errors
							)) {
								// Found the instance of just created new cart

								// Initializing the object
								$cart = new model;

								if (method_exists($cart, '__document')) {
									// Object can implement a document from ArangoDB

									// Writing the instance of cart document from ArangoDB to the implement object
									$cart->__document($result);

									// Connecting the cart to the document
									$connected = $this->connect($cart, $errors);

									if ($connected) {
										// The cart has been connected to the document

										// Exit (success)
										return $cart;
									} else throw new exception('Failed to connect the ' . model::class . ' to the ' . static::class);
								} else throw new exception('Class ' . model::class . ' does not implement a document from ArangoDB');
							} else throw new exception('Failed to create or find just created ' . static::class);
						}
					} else throw new exception('Failed to initialize ' . model::TYPE . ' collection: ' . model::COLLECTION);
				} else throw new exception('Failed to initialize ' . connect::TYPE . ' collection: ' . connect::COLLECTION);
			} else throw new exception('Failed to initialize ' . static::TYPE . ' collection: ' . static::COLLECTION);
		} catch (exception $e) {
			// Writing to the registry of errors
			$errors[] = [
				'text' => $e->getMessage(),
				'file' => $e->getFile(),
				'line' => $e->getLine(),
				'stack' => $e->getTrace()
			];
		}

		// Exit (fail)
		return null;
	}
}
