<?php

namespace Modules\RemoteData\EntityManagementWs\Model\Entity\SupplierInvoice;

class Update extends \Modules\RemoteData\EntityManagementWs\Model\Entity\UpdateAbstract
{

	/**
	 * The entity fields - so we can easily and automatically associate them in the entity (values
	 * are taken from request body). This is an associative array.
	 * @var array
	 */
	protected $entityFields = [
		'idSupplier', 'invoiceNumber', 'invoiceDate', 'currency', 'dueDate', 'fulfillmentDate', 'invoiceSeries', 'formOfPayment', 'invoiceComments', 'remarks',
	];

	/**
	 * The invoice row entity fields - so we can easily and automatically associate them in the entity (values
	 * are taken from request body) -- used for update/insert operations
	 * @var array
	 */
	private $invoiceRowEntityFields = [
		'serviceCode', 'description', 'rowType', 'externalReservationId', 'externalReservationDate', 'confirmationNumber', 'idPassenger',
		'checkIn', 'checkOut', 'contractNumber', 'ticketNo', 'idSupplierProduct', 'countryCode', 'cityId',
		'reservationCode', 'reservationNumber', 'reservationId', 'idService', 'measureUnit', 'quantity',
		'priceValue', 'vatValue', 'vatText'
	];

	/**
	 * {@inheritDoc}
	 * @see \Modules\RemoteData\EntityManagementWs\Model\Entity\InsertAbstract::initEntityObject()
	 */
	protected function initEntityObject() : \App\Entity\GeneralAbstract
	{
		return \Entity\SupplierInvoice::update($this->id);
	}

	/**
	 *
	 * {@inheritDoc}
	 * @see \Modules\RemoteData\EntityManagementWs\Model\Entity\InsertAbstract::populateEntityFields()
	 */
	protected function populateEntityFields(\App\Entity\GeneralAbstract $entityObj)
	{
		// automatically associate the entity fields to the values from the request (invoice general data)
		parent::populateEntityFields($entityObj);

		if (property_exists($this->request, 'rows')) {
			$suppInvEnt = \Entity\SupplierInvoice::selectForUpdate($this->id);
			$currentEntityRowsIdsList = array_combine(array_keys($suppInvEnt->rowsList), array_keys($suppInvEnt->rowsList));

			$finalEntityRows = [];

			// GO THROUGH THE REQUEST ROWS LIST AND APPLY THE OPERATION ///////////////////////////
			$reqRowsList = $this->request->rows;
			foreach ($reqRowsList as $rowDetails) {
				switch ($rowDetails->operation) {
					case 'insert':
						$finalEntityRows[] = $this->insertRow($rowDetails);
						break;
					case 'update':
							if ($currentEntityRowsIdsList[$rowDetails->id]) {
								$finalEntityRows[] = $this->updateRow($rowDetails);
								unset($currentEntityRowsIdsList[$rowDetails->id]);
							}
							else {
								throw new \Modules\RemoteData\EntityManagementWs\Model\RuntimeException(sprintf("Invalid invoice row id received for `update` operation (id: %s)", $rowDetails->id));
							}
						break;
					case 'delete':
							if ($currentEntityRowsIdsList[$rowDetails->id]) {
								$finalEntityRows[] = $this->deleteRow($rowDetails);
								unset($currentEntityRowsIdsList[$rowDetails->id]);
							}
							else {
								throw new \Modules\RemoteData\EntityManagementWs\Model\RuntimeException(sprintf("Invalid invoice row id received for `delete` operation (id: %s)", $rowDetails->id));
							}
						break;

					default:
						throw new \Modules\RemoteData\EntityManagementWs\Model\RuntimeException(sprintf("Unsupported operation (%s) received for row id: %s", $rowDetails->operation, $rowDetails->id));
				}
			}


			// ADD THE EXISTING / NOT MODIFIED ROWS FROM THE ENTITY AS THEY ARE ///////////////////
			if ($currentEntityRowsIdsList) {
				foreach ($currentEntityRowsIdsList as $supplierInvoiceRowId) {
					$currentRow = new \stdClass();
					$currentRow->id = $supplierInvoiceRowId;
					$finalEntityRows[] = $this->updateRow($currentRow);
				}
			}

			$entityObj->rows = $finalEntityRows;
		}
	}

	/**
	 * Insert a new invoice row
	 * @param \stdClass $rowDetails
	 * @return \Entity\SupplierInvoiceRow
	 */
	private function insertRow(\stdClass $rowDetails) : \Entity\SupplierInvoiceRow
	{
		$rowEnt = \Entity\SupplierInvoiceRow::insert();

		// populates the entity fields automatically
		foreach ($this->invoiceRowEntityFields as $entityField => $requestField) {
			if (is_numeric($entityField)) {
				if (property_exists($rowDetails, $requestField)) {
					$rowEnt->$requestField = $rowDetails->$requestField;
				}
			} else {
				if (property_exists($rowDetails, $requestField)) {
					$rowEnt->$entityField = $rowDetails->$requestField;
				}
			}
		}

		return $rowEnt;
	}

	/**
	 * @param array $requestRows
	 * @param \stdClass $rowDetails
	 * @return \Entity\SupplierInvoiceRow
	 */
	private function updateRow(\stdClass $rowDetails) : \Entity\SupplierInvoiceRow
	{
		$rowEnt = \Entity\SupplierInvoiceRow::update($rowDetails->id);
		$rowEnt->importOriginalFields();

		// populates the entity fields automatically
		foreach ($this->invoiceRowEntityFields as $entityField => $requestField) {
			if (is_numeric($entityField)) {
				if (property_exists($rowDetails, $requestField)) {
					$rowEnt->$requestField = $rowDetails->$requestField;
				}
			} else {
				if (property_exists($rowDetails, $requestField)) {
					$rowEnt->$entityField = $rowDetails->$requestField;
				}
			}
		}

		return $rowEnt;
	}

	/**
	 * Delete an existing invoice row
	 * @param \stdClass $rowDetails
	 * @return \Entity\SupplierInvoiceRow
	 */
	private function deleteRow(\stdClass $rowDetails) : \Entity\SupplierInvoiceRow
	{
		$rowEnt = \Entity\SupplierInvoiceRow::delete($rowDetails->id);
		return $rowEnt;
	}
}

