<?php
namespace SabaiApps\Framework\Model\EntityCollection;

use SabaiApps\Framework\Criteria\InCriteria;

/**
 * ForeignEntitiesEntityCollectionDecorator class for decorating entity collections with foreign entities.
 * Adds functionality to fetch and assign multiple foreign entities for each entity in the collection.
 */
class ForeignEntitiesEntityCollectionDecorator extends AbstractEntityCollectionDecorator {

	protected $_foreignSelfKey, $_foreignEntityName, $_foreignEntities, $_selfForeignVar, $_foreignEntityObjectVarName;

	/**
	 * Constructor.
	 *
	 * @param string                   $foreignSelfKey Key used to link foreign entities.
	 * @param string                   $foreignEntityName Name of the foreign entity.
	 * @param AbstractEntityCollection $collection Entity collection to decorate.
	 * @param string|null              $foreignEntityObjectVarName Variable name for the foreign entity object (optional).
	 * @param string|null              $selfForeignVar Variable name for the self foreign key (optional).
	 */
	public function __construct( $foreignSelfKey, $foreignEntityName, AbstractEntityCollection $collection, $foreignEntityObjectVarName = null, $selfForeignVar = null ) {
		parent::__construct( $collection );
		$this->_foreignSelfKey             = $foreignSelfKey;
		$this->_foreignEntityName          = $foreignEntityName;
		$this->_foreignEntityObjectVarName = isset( $foreignEntityObjectVarName ) ? $foreignEntityObjectVarName : $foreignEntityName;
		$this->_selfForeignVar             = $selfForeignVar;
	}

	/**
	 * Rewinds the collection and fetches foreign entities.
	 */
	#[\ReturnTypeWillChange]
	public function rewind() {
		$this->_collection->rewind();
		if ( ! isset( $this->_foreignEntities ) ) {
			$this->_foreignEntities = array();
			if ( $this->_collection->count() > 0 ) {
				$ids         = ! isset( $this->_selfForeignVar ) ? $this->_collection->getAllIds() : $this->_collection->getArray( $this->_selfForeignVar );
				$criteria    = new InCriteria( $this->_foreignSelfKey, $ids );
				$foreign_var = substr( $this->_foreignSelfKey, strpos( $this->_foreignSelfKey, '_' ) + 1 );
				foreach ( $this->_model->getRepository( $this->_foreignEntityName )->fetchByCriteria( $criteria ) as $entity ) {
					$this->_foreignEntities[ $entity->$foreign_var ][] = $entity;
				}
				$this->_collection->rewind();
			}
		}
	}

	/**
	 * Gets the current entity and assigns its foreign entities.
	 *
	 * @return mixed Current entity with foreign entities.
	 */
	#[\ReturnTypeWillChange]
	public function current() {
		$current  = $this->_collection->current();
		$id       = $current->id;
		$entities = ! empty( $this->_foreignEntities[ $id ] ) ? $this->_foreignEntities[ $id ] : array();
		$current->assignObject( $this->_foreignEntityObjectVarName, $this->_model->createCollection( $this->_foreignEntityName, $entities ) );

		return $current;
	}
}
