<?php
declare(strict_types = 1)
	;

namespace App\Services;

use App\DAO\AgendaDAO;
use App\DAO\DAOResponse\DAOResponseInterface;
use App\DAO\Filter\QueryFilter;
use App\DAO\Order\QueryOrder;
use App\DAO\Pagination\Pagination;
use App\Entities\Agenda\Agenda;
use App\Mappers\AgendaMapper;
use App\Services\ServiceResponse\ServiceResponse;
use App\Services\ServiceResponse\ServiceResponseInterface;
use App\Utils\Collections\GeneralCollection;
use App\Utils\Collections\QueryFilterCollection;
use App\Utils\Collections\QueryOrderCollection;
use App\Utils\ResponseException;
use App\ViewModels\Agenda\AgendaMultipleRegistrationViewModel\AgendaMultipleRegistrationViewModel;
use App\ViewModels\Agenda\AgendaRegistrationViewModel\AgendaRegistrationViewModel;

class AgendaService extends Service {

	public function registerAgenda(array $agenda_array): ServiceResponse {

		try {
			$agenda_registration_vm = AgendaMapper::getAgendaRegistrationVMFromArray( $agenda_array );
		} catch ( ResponseException $exception ) {
			return ServiceResponse::builder()->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR )
				->setErrors( $exception->getData() )
				->build();
		}
		$agenda_dao = new AgendaDAO();
		$schedules_conflicts = $this->getSchedulesConflicts( $agenda_dao, $agenda_registration_vm );
		if ($schedules_conflicts->length > 0) {
			$service_response = ServiceResponse::builder()->setStatus( ServiceResponseInterface::HAVE_CONFLICTS )
				->setErrors( [ 
				'conflitos' => $schedules_conflicts->toArray()
			] )
				->build();
		} else {
			$dao_response = $agenda_dao->persistAgendaRegistrationVM( $agenda_registration_vm );
			$service_response = new ServiceResponse();
			switch ($dao_response->getStatus()) {
				case DAOResponseInterface::SUCESS :
					$service_response->setStatus( ServiceResponseInterface::SUCESS );
					$service_response->setData( $this->getRegisterAgendaDataResponse( $dao_response->getData() ) );
					break;
				case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( $dao_response->getErrors() );
					break;
				case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( $dao_response->getErrors() );
					break;
				default :
					$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
					break;
			}
		}
		return $service_response;

	}

	public function deleteAgenda(int $id_agenda) {

		$agenda_dao = new AgendaDAO();
		$dao_response = $agenda_dao->deleteAgenda( $id_agenda );
		$service_response_status = [ 
			DAOResponseInterface::RESTRICT_FK_UPDATE_OR_DELETION => ServiceResponseInterface::RECORD_IS_LINKED,
			DAOResponseInterface::SUCESS => ServiceResponseInterface::SUCESS,
			DAOResponseInterface::RECORD_NOT_FOUND => ServiceResponseInterface::RECORD_NOT_FOUND
		] [$dao_response->getStatus()];
		$service_response = ServiceResponse::builder()->setStatus( $service_response_status )
			->build();
		return $service_response;

	}

	private function getRegisterAgendaDataResponse(Agenda $agenda): array {

		return [ 
			'id_agenda' => $agenda->getId()
		];

	}

	private function getSchedulesConflicts(AgendaDAO $agenda_dao, AgendaRegistrationViewModel $agenda_registration_vm): GeneralCollection {

		$dao_response = $agenda_dao->getAgendaConflicts( $agenda_registration_vm );
		if ($dao_response->getStatus() === DAOResponseInterface::SUCESS) {
			return $dao_response->getData();
		} else {
			return new GeneralCollection();
		}

	}

	public function getAgendaListByMedicoID(QueryFilterCollection $query_filter_collection, ?Pagination $pagination,
			QueryOrderCollection $query_order_collection): ServiceResponse {

		$agenda_dao = new AgendaDAO();
		// $query_filter_collection->push(QueryFilter::builder()
		// ->setTable('agenda')
		// ->setNameParam('id_MEDICO')
		// ->setValue($medico_id)
		// ->setIsExact(true)
		// ->build()
		// );
		$dao_response = $agenda_dao->getAgendaList( $query_filter_collection, $query_order_collection, $pagination );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response_status = ServiceResponseInterface::SUCESS;
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response_status = ServiceResponseInterface::RECORD_NOT_FOUND;
				break;
			default :
				$service_response_status = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
				break;
		}
		$service_response = ServiceResponse::builder()->setStatus( $service_response_status )
			->build();
		if ($service_response_status === DAOResponseInterface::SUCESS) {
			$dao_response_data = $dao_response->getData();
			$agenda_details_array = AgendaMapper::getAgendaListingArrayFromAgendaListingVMCollection( $dao_response_data );
			$pagination = $dao_response->getPagination();
			$data = [ 
				'agendas' => $agenda_details_array,
				'pagination' => $pagination ? $pagination->toResponseArray() : null
			];
			$service_response->setData( $data );
		}
		return $service_response;

	}

	public function registerMultipleAgenda(array $agenda_array): ServiceResponse {

		try {
			$agenda_multiple_registration_vm = AgendaMapper::getAgendaMultipleRegistrationVMFromArray( $agenda_array );
		} catch ( ResponseException $exception ) {
			return ServiceResponse::builder()->setErrors( $exception->getData() )
				->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR )
				->build();
		}
		$daily_schedules_collection = AgendaMapper::getDailySchedulesByAgendaMultipleRegistrationVM( $agenda_multiple_registration_vm );
		$service_dates_collection = AgendaMapper::getServiceDatesCollectionByAgendaMultipleRegistrationVM( $agenda_multiple_registration_vm );
		$agenda_dao = new AgendaDAO();
		$potential_conflicts = $this->getMultipleRegisterAgendaConflictsCollection( $agenda_dao, $agenda_multiple_registration_vm, $service_dates_collection );
		$conflicts = new GeneralCollection();
		$agenda_collection = AgendaMapper::getAgendaCollectionBySchedulesAndDates( $agenda_multiple_registration_vm, $daily_schedules_collection,
			$service_dates_collection, $potential_conflicts, $conflicts );
		if ($agenda_collection->length > 0) {
			$dao_response = $agenda_dao->persistAgendaCollection( $agenda_collection );
			$dao_response_status = $dao_response->getStatus();
			$service_response = new ServiceResponse();
			if (in_array( $dao_response_status, [ 
				DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS,
				DAOResponseInterface::DUPLICATED_UNIQUE_KEY
			] )) {
				$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
				$service_response->setErrors( $dao_response->getErrors() );
			} else if ($dao_response_status === DAOResponseInterface::SUCESS) {
				if ($conflicts->length) {
					$service_response->setStatus( ServiceResponseInterface::PARTIAL_SUCESS );
					$service_response->setErrors( [ 
						'conflitos' => $conflicts->toArray()
					] );
				} else {
					$service_response->setStatus( ServiceResponseInterface::SUCESS );
				}
			} else {
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
			}
			return $service_response;
		} else {
			return ServiceResponse::builder()->setStatus( ServiceResponseInterface::HAVE_CONFLICTS )
				->setErrors( [ 
				'conflitos' => $conflicts->toArray()
			] )
				->build();
		}

	}

	private function getMultipleRegisterAgendaConflictsCollection(AgendaDAO $agenda_dao, AgendaMultipleRegistrationViewModel $agenda_multiple_registration_vm,
			GeneralCollection $service_dates_collection): GeneralCollection {

		$dao_response = $agenda_dao->getAgendaConflictsForMultipleRegistration( $agenda_multiple_registration_vm, $service_dates_collection );
		return $dao_response->getStatus() === DAOResponseInterface::SUCESS ? $dao_response->getData() : new GeneralCollection();

	}

	public function updateAgenda(int $id_agenda, array $data): ServiceResponse {

		$agenda_update_vm = AgendaMapper::getAgendaUpdateVMFromArray( $data );
		$agenda_dao = new AgendaDAO();
		$dao_response = $agenda_dao->updateAgenda( $id_agenda, $agenda_update_vm );
		$service_response = new ServiceResponse();
		$response_status = [ 
			DAOResponseInterface::SUCESS => ServiceResponseInterface::SUCESS,
			DAOResponseInterface::RECORD_NOT_FOUND => ServiceResponseInterface::RECORD_NOT_FOUND,
			DAOResponseInterface::DATABASE_CONNECTION_ERROR => ServiceResponseInterface::DATABASE_CONNECTION_ERROR,
			DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS => ServiceResponseInterface::VALIDATION_PARAMS_ERROR
		] [$dao_response->getStatus()];
		if (!$response_status) {
			(new LogService())->log_error( $response_status, "Ocorreu um erro desconhecido durante a atualização da agenda", [ ] );
			$response_status = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
		} else if ($response_status !== ServiceResponseInterface::SUCESS) {
			$service_response->setErrors( $dao_response->getErrors() );
		}
		$service_response->setStatus( $response_status );
		return $service_response;

	}

}
