<?php

namespace App\AutoProcessRules;

class ImportedServiceProcess_RecordsList extends RecordsListAbstract
{

	/**
	 * (non-PHPdoc)
	 * @see \App\AutoProcessRules\RecordsListAbstract::getRecords()
	 */
	public function getRecords()
	{

		// GET RULE DETAILS -----------------------------------------------------------------------
		$ruleEnt	= \Entity\AutoProcessRule::select($this->idRule);
		$ruleObj	= $ruleEnt->object;
		$filters	= $this->getFilters();
		$fields		= $ruleObj->getFields();

		// GET BULK RECORDS -----------------------------------------------------------------------
		$importedServicesListObj = new \App\EntityList\ImportedServices();
		$this->populateListObject($importedServicesListObj, $filters, $fields);
		$importedServicesListEx = $importedServicesListObj->getExecution();

		// GROUP THE RECORDS ----------------------------------------------------------------------
		$records = [];
		foreach ($importedServicesListEx as $record) {

			$key = null;
			switch ($ruleObj->getField('processGrouping')) {
				case 'one':
					$key = $record['idService'];
					break;
				case 'order':
					$key = $record['idOrder'];
					break;
				case 'day':
					$key = $record['date'];
					break;
				case 'day/client':
					$filters = $this->getFilters();
					if ($filters['clientType'] == 'corporate') {
						$key = $record['date'].'_'.$record['idCorporateOwner'];
					} else {
						$key = $record['date'].'_'.$record['idCustomerOwner'];
					}
					break;
				case 'serviceRemark':
					if (array_key_exists('groupByServiceRemarkValue', $record)) { // if only grouping by remark is done (without filtering bu remarks) when we already have the value (it's faster this way)
						$key = $record['groupByServiceRemarkValue']; // this is never blank as it is filtered below
					} else {
						$servRms = \Entity\ImportedService::select($record['idService'])->processedRemarks;
						if (strlen($servRms[$fields['groupByServiceRemarkVar']])) {
							$key = $servRms[$fields['groupByServiceRemarkVar']];
						} // if the groupByServiceRemarkVar value is not set for the current service, it will be skipped ($key remains null)
					}
					break;
				case 'all':
					$key = 'all'; // it must be filled in, otherwise it is skipped
					break;
				case 'all/client':
					$filters = $this->getFilters();
					if ($filters['clientType'] == 'corporate') {
						$key = $record['idCorporateOwner'].'_'.$record['ownerCorporate'];
					} else {
						$key = $record['idCustomerOwner'];
					}
					break;
			}

			if ($key) { // skips serviceRemark grouping when the remark doesn't have a value
				$records[$key][] = $record;
			}

		}

		// SLICE THE LIST OF RECORDS --------------------------------------------------------------
		$records = $this->sliceRecords($records);

		return $records;

	}


	/**
	 * Populates the $importedServicesListObj with columns, filters, etc.
	 * @param \App\EntityList\ImportedServices $importedServicesListObj
	 * @param array $filters
	 */
	protected function populateListObject(\App\EntityList\ImportedServices $importedServicesListObj, Array $filters, Array $fields)
	{

		// ADD COLUMNS ----------------------------------------------------------------------------
		$importedServicesListObj->setColumns( ['importedOrder.date', 'importedOrder.idSystem', 'importedOrder.id'=>'idOrder', 'importedService.id'=>'idService', 'importedOrder.idCorporateOwner' => 'idCorporateOwner', 'importedOrder.ownerCorporate', 'importedOrder.idCustomerOwner' => 'idCustomerOwner', ] );

		// ADD FILTERS ----------------------------------------------------------------------------

		// add standard filters
		$importedServicesListObj->setFilter('importedService.processStatus', '=', 'new');
		$importedServicesListObj->setFilter('importedService.systemStatus', 'IN', ['request', 'confirmed', 'refunded']);
		$importedServicesListObj->setFilter('importedService.isPackage', '=', '0');

		// apply client type filter
		if ($filters['clientType'] == 'corporate') {
			$importedServicesListObj->setCustomFilter('importedOrder.idCorporateOwner!=? OR importedOrder.ownerCorporate!=?', [0, '']);

			// apply filter for owner corporate if necessary
			if ($filters['corporates']) {
				$importedServicesListObj->setFilter('importedOrder.idCorporateOwner', 'IN', $filters['corporates']);
			}

			// apply corporate segment filtering
			if ($filters['corporateGroups']) {
				$corporateGroupsHelper = new \App\ReportsData\Helpers\PartnerGroups\Corporate();
				$corporateGroupsHelper->setGroupElementsLinear($filters['corporateGroups']);
				$idCorporatesList = $corporateGroupsHelper->getPartnerIdsList();
				if ($idCorporatesList) {
					$importedServicesListObj->setFilter('importedOrder.idCorporateOwner', 'IN', $idCorporatesList);
				} else {
					$importedServicesListObj->setCustomFilter('0');
				}
			}

		} else {
			$importedServicesListObj->setFilter('importedOrder.idCorporateOwner', '=', 0);
			$importedServicesListObj->setFilter('importedOrder.ownerCorporate', '=', '');

			// apply filter for owner customer if necessary
			if ($filters['customers']) {
				$importedServicesListObj->setFilter('importedOrder.idCustomerOwner', 'IN', $filters['customers']);
			}
		}

		// service code filter
		if ($filters['serviceCodes']) {
			$importedServicesListObj->setFilter('importedService.serviceCode', 'IN', $filters['serviceCodes']);
		}


		// offer supplier filter
		if ($filters['offerSuppliers']) {
			if ($filters['supplierApplyMode'] == 'excluded') {
				$importedServicesListObj->setFilter('importedService.idOfferSupplier', 'NOT IN', $filters['offerSuppliers']);
			}
			else {
				$importedServicesListObj->setFilter('importedService.idOfferSupplier', 'IN', $filters['offerSuppliers']);
			}
		}

		// offer supplier category filter
		if ($filters['offerSupplierCategory']) {
			$importedServicesListObj->setFilter('offerSupplier.category', 'IN', $filters['offerSupplierCategory']);
		}

		// offer currency
		if ($filters['offerCurrencies']) {
			$importedServicesListObj->setFilter('importedService.offerTotalCurrency', 'IN', $filters['offerCurrencies']);
		}

		// filter by service user/office
		if ($filters['serviceUsers']) {
			switch ($filters['serviceUsersSource']) {
				case 'responsible':
					$importedServicesListObj->setFilter('importedService.idUser', 'IN', $filters['serviceUsers']);
				break;
				case 'issue':
					$importedServicesListObj->setFilter('importedService.idIssueUser', 'IN', $filters['serviceUsers']);
				break;
				case 'book':
					$importedServicesListObj->setFilter('importedService.idBookUser', 'IN', $filters['serviceUsers']);
				break;
				case 'any':
					$bindVarsUsersString = "(".implode(",", array_fill(0, count($filters['serviceUsers']), "?")).")";
					$customSQLForAnyUser = sprintf('importedService.idUser IN %s OR importedService.idIssueUser IN %s OR importedService.idBookUser IN %s', $bindVarsUsersString, $bindVarsUsersString, $bindVarsUsersString);
					$importedServicesListObj->setCustomFilter($customSQLForAnyUser, array_merge($filters['serviceUsers'], $filters['serviceUsers'], $filters['serviceUsers']));
				break;
			}
		}
		if ($filters['serviceOffices']) {
			switch ($filters['serviceUsersSource']) {
				case 'responsible':
					$importedServicesListObj->setFilter('importedService.idOffice', 'IN', $filters['serviceOffices']);
				break;
				case 'issue':
					$importedServicesListObj->setFilter('importedService.idIssueOffice', 'IN', $filters['serviceOffices']);
				break;
				case 'book':
					$importedServicesListObj->setFilter('importedService.idBookOffice', 'IN', $filters['serviceOffices']);
				break;
				case 'any':
					$bindVarsOfficesString = "(".implode(",", array_fill(0, count($filters['serviceOffices']), "?")).")";
					$customSQLForAnyOffice = sprintf('importedService.idOffice IN %s OR importedService.idIssueOffice IN %s OR importedService.idBookOffice IN %s', $bindVarsOfficesString, $bindVarsOfficesString, $bindVarsOfficesString);
					$importedServicesListObj->setCustomFilter($customSQLForAnyOffice, array_merge($filters['serviceOffices'], $filters['serviceOffices'], $filters['serviceOffices']));
				break;
			}
		}

		// filter: orderExternalSystems
		if ($filters['orderExternalSystems']) {
			$importedServicesListObj->setFilter('importedService.idSystem', 'IN', $filters['orderExternalSystems']);
		}

		// filter: formOfPayment
		if ($filters['formOfPayment']) {
			$importedServicesListObj->setFilter('importedService.offerFormOfPayment', 'IN', $filters['formOfPayment']);
		}

		// filter: formOfCashing
		if ($filters['formOfCashing']) {
			$importedServicesListObj->setFilter('importedService.offerFormOfCashing', 'IN', $filters['formOfCashing']);
		}

		// order date
		if ($filters['orderDate']) {
			$startDate = $filters['orderDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedOrder.date', '>=', $startDate);
			}
			$endDate = $filters['orderDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedOrder.date', '<=', $endDate);
			}
		}
		// service Add date
		if ($filters['serviceAddDate']) {
			$startDate = $filters['serviceAddDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedService.addTime', '>=', $startDate.' 00:00:00');
			}
			$endDate = $filters['serviceAddDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedService.addTime', '<=', $endDate.' 23:59:59');
			}
		}
		// service start date
		if ($filters['serviceStartDate']) {
			$startDate = $filters['serviceStartDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedService.startDate', '>=', $startDate);
			}
			$endDate = $filters['serviceStartDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedService.startDate', '<=', $endDate);
			}
		}
		// service end date
		if ($filters['serviceEndDate']) {
			$startDate = $filters['serviceEndDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setCustomFilter('importedService.endDate>=? OR (importedService.endDate = ? AND importedService.startDate>=?)', [$startDate, '0000-00-00', $startDate]);
			}
			$endDate = $filters['serviceEndDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setCustomFilter('importedService.endDate<=? OR (importedService.endDate = ? AND importedService.startDate<=?)', [$endDate, '0000-00-00', $endDate]);
			}
		}
		// ticket date
		if ($filters['ticketDate']) {
			$startDate = $filters['ticketDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedTickets.ticketDate', '>=', $startDate);
			}
			$endDate = $filters['ticketDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedTickets.ticketDate', '<=', $endDate);
			}

			// eliminate duplicate services (multiple tickets conditions can be met)
			$importedServicesListObj->setGroupBy('importedTickets.idImportedService');
		}

		// get corporations that have the correct remark set - ad then filter by these corporations
		if ($filters['corporateRemarks']) {

			$corpRmList = new \App\EntityList\Corporates();

			foreach($filters['corporateRemarks'] as $rmDet) {
				$corpRmList->setFilter('remarks.var', '=', $rmDet['var']);
				// set the remarks values
				if ($rmDet['op']=='equal') {
					$corpRmList->setFilter('remarks.value', 'IN', $rmDet['val']);
				}
				elseif ($rmDet['op']=='notEqual') {
					$corpRmList->setFilter('remarks.value', 'NOT IN', $rmDet['val']);
				}
				elseif ($rmDet['op']=='noValue') {
					$corpRmList->setFilter('remarks.value', '=', '');
				}
				elseif ($rmDet['op']=='anyValue') {
					$corpRmList->setFilter('remarks.value', '!=', '');
				}
			}
			// we will not eliminate duplicate services (multiple remark conditions can be met but the corporates ids list is checked using "IN")

			// force a limit so that the final SQL is not huge
			$corpRmList->setLimit(10000);

			// get the list of corporate ids
			$corpRows = $corpRmList->exportRecords();
			$corpsList = [];
			foreach($corpRows as $corp) {
				$corpsList[] = $corp['id'];
			}

			// filter by the list of corporate ids
			if ($corpsList) {
				$importedServicesListObj->setFilter('importedOrder.idCorporateOwner', 'IN', $corpsList);
			} else {
				$importedServicesListObj->setFilter('importedService.id', '=', 0); // no corporations found, force "no rows"
			}

		}


		// service remarks
		if ($filters['serviceRemarks']) {

			foreach($filters['serviceRemarks'] as $rmDet) {
				$importedServicesListObj->setFilter('importedServiceRemarks.var', '=', $rmDet['var']);
				// set the remarks values
				if ($rmDet['op']=='equal') {
					$importedServicesListObj->setFilter('importedServiceRemarks.value', 'IN', $rmDet['val']);
				}
				elseif ($rmDet['op']=='notEqual') {
					$importedServicesListObj->setFilter('importedServiceRemarks.value', 'NOT IN', $rmDet['val']);
				}
				elseif ($rmDet['op']=='noValue') {
					$importedServicesListObj->setFilter('importedServiceRemarks.value', '=', '');
				}
				elseif ($rmDet['op']=='anyValue') {
					$importedServicesListObj->setFilter('importedServiceRemarks.value', '!=', '');
				}
			}

			// eliminate duplicate services (multiple remark conditions can be met)
			$importedServicesListObj->setGroupBy('importedServiceRemarks.idImportedService');

		}

		// offer ext system order date
		if ($filters['offerExtSysOrderDate']) {
			$startDate = $filters['offerExtSysOrderDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedService.offerExternalSystemReservationDate', '>=', $startDate);
			}
			$endDate = $filters['offerExtSysOrderDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedService.offerExternalSystemReservationDate', '<=', $endDate);
			}
		}

		// option date
		if ($filters['offerOptionDate']) {
			$startDate = $filters['offerOptionDate']->getStartDate()->getActualDate();
			if ($startDate) {
				$importedServicesListObj->setFilter('importedService.offerOptionDate', '>=', $startDate);
			}
			$endDate = $filters['offerOptionDate']->getEndDate()->getActualDate();
			if ($endDate) {
				$importedServicesListObj->setFilter('importedService.offerOptionDate', '<=', $endDate);
			}
		}

		// if processGrouping = serviceRemark filter by groupByServiceRemarkVar;
		// we cannot filterin the same joined tables by two remarks at the same time; if the serviceRemarks is set, we will not filter by the grouped serviceRemark
		if ($fields['processGrouping']=='serviceRemark' and !$filters['serviceRemarks']) {
			$importedServicesListObj->setFilter('importedServiceRemarks.var', '=', $fields['groupByServiceRemarkVar']);
			$importedServicesListObj->setFilter('importedServiceRemarks.value', '!=', '');
			$importedServicesListObj->setColumn('importedServiceRemarks.value', 'groupByServiceRemarkValue');
		}

		// offer criterion
		if ($filters['offerCriterion']) {
			$importedServicesListObj->setFilter('importedService.offerCriterion', 'IN', $filters['offerCriterion']);
		}

		// system status
		if ($filters['externalSystemStatus']) {
			$importedServicesListObj->setFilter('importedService.systemStatus', 'IN', $filters['externalSystemStatus']);
		}

		// reissue status
		if ($filters['reissueStatus']=='nonReissue') {
			$importedServicesListObj->setFilter('importedService.idImportedServiceReissued', '=', 0);
		} elseif ($filters['reissueStatus']=='reissue') {
			$importedServicesListObj->setFilter('importedService.idImportedServiceReissued', '>', 0);
		}

		// apply order by - chronologically
		$importedServicesListObj->setOrderBy('importedService.id', 'ASC');

	}


	/**
	 * Limits the number of records exported.
	 * @param Array $records
	 * @return Array
	 */
	protected function sliceRecords(Array $records)
	{

		$ruleEnt = \Entity\AutoProcessRule::select($this->idRule);

		if (!$ruleEnt->recordsCountOnExecution) {
			return $records;
		} else {
			return array_slice($records, 0, $ruleEnt->recordsCountOnExecution, true);
		}

	}

}

