<?php

namespace App\Services;

use App\DAO\AgendaDAO;
use App\DAO\AgendamentoDAO;
use App\DAO\ConsultaDAO;
use App\DAO\DAOResponse\DAOResponse;
use App\DAO\DAOResponse\DAOResponseInterface;
use App\DAO\FormularioDAO;
use App\DAO\PacienteDAO;
use App\DAO\Pagination\Pagination;
use App\Mappers\ConsultaMapper;
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\Consulta\ConsultaDetailsViewModel\ConsultaDetailsViewModel;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\ConsultaRegistrationViewModel;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\RespostaEscolhaOpcao;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\RespostaFormularioAbstract;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\RespostaNumericaDecimal;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\RespostaNumericaInteira;
use App\ViewModels\Consulta\ConsultaRegistrationViewModel\RespostaTextual;
use App\ViewModels\Formulario\PerguntaDetailsViewModel\PerguntaDetailsViewModel;
use App\ViewModels\Formulario\PerguntaOpcoesViewModel\PerguntaOpcoesViewModel;

class ConsultaService extends Service {

	public function registerConsulta(array $data_post): ServiceResponse {

		$service_response = new ServiceResponse();
		$consulta_registration_vm = ConsultaMapper::getConsultaRegistrationVMFromArray( $data_post );
		$agendamento_dao = new AgendamentoDAO();
		$jwt_payload = JWTService::getTokenJWTPayload();
		if (!$agendamento_dao->medicoIsLinkedToAgendamento( $jwt_payload->getUid(), $consulta_registration_vm->getIdAgendamento() )) {
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$service_response->setErrors( [ 
				'id_agendamento' => 'Esse médico não está vinculado a esse agendamento.'
			] );
			return $service_response;
		}
		$formulario_dao = new FormularioDAO();
		$formulario_dao_response = $formulario_dao->getPerguntasByIdAgendamento( $consulta_registration_vm->getIdAgendamento(), $data_post );
		$pergunta_details_vm_collection = $formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS ? $this->getGeneralCollectionFromDAOResponse( 
			$formulario_dao_response ) : new GeneralCollection();
		// $this->changeQuestionYesOrNoToZeroAndOne ($pergunta_details_vm_collection, $consulta_registration_vm);
		$wrong_perguntas = $this->getMissingPerguntaFromConsultaRegistrationVM( $consulta_registration_vm, $pergunta_details_vm_collection );
		if ($wrong_perguntas->length > 0) { // Valida as perguntas obrigatórias e as de tipagem errada.
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$errors = $this->getPerguntaErrors( $wrong_perguntas );
			$service_response->setErrors( $errors );
			return $service_response;
		} else {
			$consulta_dao = new ConsultaDAO();
			$consulta_dao_response = $consulta_dao->registerConsulta( $consulta_registration_vm, $data_post );
			$formulario_dao_response = $formulario_dao->getPerguntasOpcoesByIdsPerguntas( $consulta_registration_vm->getRespostaEscolhaOpcaoCollection() );
			if ($formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS) {
				$opcoes_perguntas_vm_collection = $this->getGeneralCollectionFromDAOResponse( $formulario_dao_response );
				$id_opcao_pergunta_wrong = 0;
				$wrong_resposta_escolha_opcao = $this->getWrongRespostaEscolhaOpcao( $consulta_registration_vm, $opcoes_perguntas_vm_collection,
					$id_opcao_pergunta_wrong );
				if ($wrong_resposta_escolha_opcao) {
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( 
						[ 
							'pergunta' => [ 
								'id' => $wrong_resposta_escolha_opcao->getIdPergunta(),
								'id_opcao_pergunta' => $id_opcao_pergunta_wrong
							]
						] );
					return $service_response;
				}
			}

			$consulta_dao_data = $consulta_dao_response->getData();
			switch ($consulta_dao_response->getStatus()) {
				case DAOResponseInterface::SUCESS :
					$service_response->setData( [ 
						"consulta_id" => $consulta_dao_data ["consulta_id"]
					] );
					$service_response->setStatus( ServiceResponseInterface::SUCESS );
					break;
				case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
				case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( $consulta_dao_response->getErrors() );
					break;
				default :
					$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
					break;
			}

			return $service_response;
		}

	}

	public function registerConsultaRequisicao(array $data_post): ServiceResponse {

		$agenda_dao = new ConsultaDAO();
		$id_agendamento = $agenda_dao->registerAgendamentoBaseRequisicao( $data_post );
		$data_post ['id_agendamento'] = $id_agendamento;

		$service_response = new ServiceResponse();
		$consulta_registration_vm = ConsultaMapper::getConsultaRegistrationVMFromArray( $data_post );
		// $agendamento_dao = new AgendamentoDAO();
		// $jwt_payload = JWTService::getTokenJWTPayload();
		// if (! $agendamento_dao->medicoIsLinkedToAgendamento( $jwt_payload->getUid(), $consulta_registration_vm->getIdAgendamento() )) {
		// $service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
		// $service_response->setErrors( [
		// 'id_agendamento' => 'Esse médico não está vinculado a esse agendamento.' ] );
		// return $service_response;
		// }
		$formulario_dao = new FormularioDAO();
		$formulario_dao_response = $formulario_dao->getPerguntasByIdAgendamento( $consulta_registration_vm->getIdAgendamento(), $data_post );
		$pergunta_details_vm_collection = $formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS ? $this->getGeneralCollectionFromDAOResponse( 
			$formulario_dao_response ) : new GeneralCollection();
		// $this->changeQuestionYesOrNoToZeroAndOne ($pergunta_details_vm_collection, $consulta_registration_vm);
		$wrong_perguntas = $this->getMissingPerguntaFromConsultaRegistrationVM( $consulta_registration_vm, $pergunta_details_vm_collection );
		if ($wrong_perguntas->length > 0) { // Valida as perguntas obrigatórias e as de tipagem errada.
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$errors = $this->getPerguntaErrors( $wrong_perguntas );
			$service_response->setErrors( $errors );
			return $service_response;
		} else {
			$consulta_dao = new ConsultaDAO();
			$consulta_dao_response = $consulta_dao->registerConsultaRequisicao( $consulta_registration_vm, $data_post );
			$formulario_dao_response = $formulario_dao->getPerguntasOpcoesByIdsPerguntas( $consulta_registration_vm->getRespostaEscolhaOpcaoCollection() );
			if ($formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS) {
				$opcoes_perguntas_vm_collection = $this->getGeneralCollectionFromDAOResponse( $formulario_dao_response );
				$id_opcao_pergunta_wrong = 0;
				$wrong_resposta_escolha_opcao = $this->getWrongRespostaEscolhaOpcao( $consulta_registration_vm, $opcoes_perguntas_vm_collection,
					$id_opcao_pergunta_wrong );
				if ($wrong_resposta_escolha_opcao) {
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( 
						[ 
							'pergunta' => [ 
								'id' => $wrong_resposta_escolha_opcao->getIdPergunta(),
								'id_opcao_pergunta' => $id_opcao_pergunta_wrong
							]
						] );
					return $service_response;
				}
			}

			$consulta_dao_data = $consulta_dao_response->getData();
			switch ($consulta_dao_response->getStatus()) {
				case DAOResponseInterface::SUCESS :
					$service_response->setData( [ 
						"consulta_id" => $consulta_dao_data ["consulta_id"]
					] );
					$service_response->setStatus( ServiceResponseInterface::SUCESS );
					break;
				case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
				case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( $consulta_dao_response->getErrors() );
					break;
				default :
					$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
					break;
			}

			return $service_response;
		}

	}


    public function registerConsultaTelevet(array $data_post): ServiceResponse {

        $agenda_dao = new ConsultaDAO();
        $service_response = new ServiceResponse();
        $consulta_registration_vm = ConsultaMapper::getConsultaRegistrationVMFromArray( $data_post );

        $formulario_dao = new FormularioDAO();
        $formulario_dao_response = $formulario_dao->getPerguntasByIdAgendamento( $consulta_registration_vm->getIdAgendamento(), $data_post );
        $pergunta_details_vm_collection = $formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS ? $this->getGeneralCollectionFromDAOResponse(
            $formulario_dao_response ) : new GeneralCollection();
        // $this->changeQuestionYesOrNoToZeroAndOne ($pergunta_details_vm_collection, $consulta_registration_vm);
        $wrong_perguntas = $this->getMissingPerguntaFromConsultaRegistrationVM( $consulta_registration_vm, $pergunta_details_vm_collection );
        if ($wrong_perguntas->length > 0) { // Valida as perguntas obrigatórias e as de tipagem errada.
            $service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
            $errors = $this->getPerguntaErrors( $wrong_perguntas );
            $service_response->setErrors( $errors );
            return $service_response;
        } else {
            $consulta_dao = new ConsultaDAO();
            $consulta_dao_response = $consulta_dao->registerConsultaRequisicao( $consulta_registration_vm, $data_post );
            $formulario_dao_response = $formulario_dao->getPerguntasOpcoesByIdsPerguntas( $consulta_registration_vm->getRespostaEscolhaOpcaoCollection() );
            if ($formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS) {
                $opcoes_perguntas_vm_collection = $this->getGeneralCollectionFromDAOResponse( $formulario_dao_response );
                $id_opcao_pergunta_wrong = 0;
                $wrong_resposta_escolha_opcao = $this->getWrongRespostaEscolhaOpcao( $consulta_registration_vm, $opcoes_perguntas_vm_collection,
                    $id_opcao_pergunta_wrong );
                if ($wrong_resposta_escolha_opcao) {
                    $service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
                    $service_response->setErrors(
                        [
                            'pergunta' => [
                                'id' => $wrong_resposta_escolha_opcao->getIdPergunta(),
                                'id_opcao_pergunta' => $id_opcao_pergunta_wrong
                            ]
                        ] );
                    return $service_response;
                }
            }

            $consulta_dao_data = $consulta_dao_response->getData();
            switch ($consulta_dao_response->getStatus()) {
                case DAOResponseInterface::SUCESS :
                    $service_response->setData( [
                        "consulta_id" => $consulta_dao_data ["consulta_id"]
                    ] );
                    $service_response->setStatus( ServiceResponseInterface::SUCESS );
                    break;
                case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
                case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
                    $service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
                    $service_response->setErrors( $consulta_dao_response->getErrors() );
                    break;
                default :
                    $service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
                    break;
            }

            return $service_response;
        }

    }

    public function registerConsultaMultipleRequisicao(array $data_post): ServiceResponse {

        $service_response = new ServiceResponse();
        $consultas_criadas = [];

        foreach ($data_post['id_requisicao_procedimento'] as $key => $id_requisicao_procedimento) {
            $agenda_dao = new ConsultaDAO();
            $id_agendamento = $agenda_dao->registerAgendamentoMultipleBaseRequisicao( $data_post, $id_requisicao_procedimento, $key );
            $data_post ['id_agendamento'] = $id_agendamento;

            $consulta_registration_vm = ConsultaMapper::getConsultaRegistrationVMFromArray( $data_post );
            $formulario_dao = new FormularioDAO();
            $formulario_dao_response = $formulario_dao->getPerguntasByIdAgendamento( $consulta_registration_vm->getIdAgendamento(), $data_post );
            $pergunta_details_vm_collection = $formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS ? $this->getGeneralCollectionFromDAOResponse(
                $formulario_dao_response ) : new GeneralCollection();
            $wrong_perguntas = $this->getMissingPerguntaFromConsultaRegistrationVM( $consulta_registration_vm, $pergunta_details_vm_collection );
            if ($wrong_perguntas->length > 0) { // Valida as perguntas obrigatórias e as de tipagem errada.
                $service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
                $errors = $this->getPerguntaErrors( $wrong_perguntas );
                $service_response->setErrors( $errors );
                return $service_response;
            } else {
                $consulta_dao = new ConsultaDAO();
                $consulta_dao_response = $consulta_dao->registerConsultaMultipleRequisicao($consulta_registration_vm, $data_post, $id_requisicao_procedimento);
                $formulario_dao_response = $formulario_dao->getPerguntasOpcoesByIdsPerguntas($consulta_registration_vm->getRespostaEscolhaOpcaoCollection());
                if ($formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS) {
                    $opcoes_perguntas_vm_collection = $this->getGeneralCollectionFromDAOResponse($formulario_dao_response);
                    $id_opcao_pergunta_wrong = 0;
                    $wrong_resposta_escolha_opcao = $this->getWrongRespostaEscolhaOpcao($consulta_registration_vm, $opcoes_perguntas_vm_collection,
                        $id_opcao_pergunta_wrong);
                    if ($wrong_resposta_escolha_opcao) {
                        $service_response->setStatus(ServiceResponseInterface::VALIDATION_PARAMS_ERROR);
                        $service_response->setErrors(
                            [
                                'pergunta' => [
                                    'id' => $wrong_resposta_escolha_opcao->getIdPergunta(),
                                    'id_opcao_pergunta' => $id_opcao_pergunta_wrong
                                ]
                            ]);
                        return $service_response;
                    }
                }

                $consulta_dao_data = $consulta_dao_response->getData();
                $consultas_criadas[$id_requisicao_procedimento] = [
                    "consulta_id" => $consulta_dao_data["consulta_id"],
                    "requisicao_procedimento" => $id_requisicao_procedimento,
                ];
            }

            $service_response->setData($consultas_criadas);
            $service_response->setStatus(ServiceResponseInterface::SUCESS);

        }
        return $service_response;
    }




	public function updateConsultaData(int $id_consulta, array $data): ServiceResponse {

		try {
			$consulta_update_vm = ConsultaMapper::getConsultaUpdateVMFromArray( $data );

			if (count( $consulta_update_vm->toArray( true ) ) === 0) {
				return ServiceResponse::builder()->setStatus( ServiceResponseInterface::INSUFFICIENT_DATA )
					->build();
			}
		} catch ( ResponseException $response_exception ) {
			$log_service = new LogService();
			$log_service->log_error( ServiceResponseInterface::SERVICE_INTERNAL_ERROR,
				'Ocorreu um erro durante o mapeamento da entidade ConsultaUpdateViewModel', $response_exception->getData() );
			return ServiceResponse::builder()->setStatus( ServiceResponseInterface::SERVICE_INTERNAL_ERROR )
				->setErrors( $response_exception->getData() )
				->build();
		}

		$assistente_dao = new ConsultaDAO();
		$dao_response = $assistente_dao->persistConsultaUpdateVM( $id_consulta, $consulta_update_vm );
		$service_response = new ServiceResponse();
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				break;
			case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
			case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
				$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
				$service_response->setErrors( $dao_response->getErrors() );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	# Novo Endpoint
	public function getConsultaPacienteByMedicoList(int $id_paciente, ?Pagination $pagination, QueryFilterCollection $query_filter_collection,
			QueryOrderCollection $query_order_collection): ServiceResponse {

		$service_response = new ServiceResponse();
		$log_service = new LogService();
		$consulta_dao = new ConsultaDAO();
		$dao_response = $consulta_dao->getConsultaByMedicoList( $id_paciente, $pagination, $query_filter_collection, $query_order_collection );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
					return $formulario_listing_vm;
				})( $dao_response->getData() );
				$formulario_listing_array = ConsultaMapper::getConsultaByMedicoArrayFromVM( $formulario_listing_vm );
				$pagination = $dao_response->getPagination();
				$data = [ 
					'pacientes' => $formulario_listing_array,
					'pagination' => $pagination ? $pagination->toResponseArray() : null
				];
				$service_response->setData( $data );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

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

		$service_response = new ServiceResponse();
		$jwtPayload = JWTService::getTokenJWTPayload();
		$user_is_paciente = $jwtPayload->getProfile() === PERFIL_PACIENTE;
		$user_id_paciente = $user_is_paciente ? (new PacienteDAO())->getPacienteIDFromUsuarioID( $jwtPayload->getUid() ) : 0;
		if ($user_is_paciente && $id_paciente !== $user_id_paciente) {
			$service_response->setStatus( ServiceResponseInterface::FORBIDDEN );
			return $service_response;
		}
		$log_service = new LogService();
		$consulta_dao = new ConsultaDAO();
		$dao_response = $consulta_dao->getConsultaList( $id_paciente, $pagination, $query_filter_collection, $query_order_collection );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
					return $formulario_listing_vm;
				})( $dao_response->getData() );
				$formulario_listing_array = ConsultaMapper::getConsultaListingArrayFromVM( $formulario_listing_vm );
				$pagination = $dao_response->getPagination();
				$data = [ 
					'consultas' => $formulario_listing_array,
					'pagination' => $pagination ? $pagination->toResponseArray() : null
				];
				$service_response->setData( $data );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

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

		$service_response = new ServiceResponse();
		$jwtPayload = JWTService::getTokenJWTPayload();
		$user_is_paciente = $jwtPayload->getProfile() === PERFIL_PACIENTE;
		$user_id_paciente = $user_is_paciente ? (new PacienteDAO())->getPacienteIDFromUsuarioID( $jwtPayload->getUid() ) : 0;
		if (!($user_is_paciente && $id_paciente !== $user_id_paciente)) {
			$service_response->setStatus( ServiceResponseInterface::FORBIDDEN );
			return $service_response;
		}
		$log_service = new LogService();
		$consulta_dao = new ConsultaDAO();
		$dao_response = $consulta_dao->getMinhasConsultasList( $id_paciente, $pagination, $query_filter_collection, $query_order_collection );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
					return $formulario_listing_vm;
				})( $dao_response->getData() );
				$formulario_listing_array = ConsultaMapper::getConsultaListingArrayFromVM( $formulario_listing_vm );
				$pagination = $dao_response->getPagination();
				$data = [ 
					'consultas' => $formulario_listing_array,
					'pagination' => $pagination ? $pagination->toResponseArray() : null
				];
				$service_response->setData( $data );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

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

        $service_response = new ServiceResponse();
        $jwtPayload = JWTService::getTokenJWTPayload();
        $user_is_paciente = $jwtPayload->getProfile() === PERFIL_PACIENTE;
        $user_id_paciente = $user_is_paciente ? (new PacienteDAO())->getPacienteIDFromUsuarioID( $jwtPayload->getUid() ) : 0;
        if (!($user_is_paciente && $id_paciente !== $user_id_paciente)) {
            $service_response->setStatus( ServiceResponseInterface::FORBIDDEN );
            return $service_response;
        }
        $log_service = new LogService();
        $consulta_dao = new ConsultaDAO();
        $dao_response = $consulta_dao->getMinhasConsultasListTelevet( $id_paciente, $pagination, $query_filter_collection, $query_order_collection );
        switch ($dao_response->getStatus()) {
            case DAOResponseInterface::SUCESS :
                $service_response->setStatus( ServiceResponseInterface::SUCESS );
                $formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
                    return $formulario_listing_vm;
                })( $dao_response->getData() );
                $formulario_listing_array = ConsultaMapper::getConsultaListingArrayFromVM( $formulario_listing_vm );
                $pagination = $dao_response->getPagination();
                $data = [
                    'consultas' => $formulario_listing_array,
                    'pagination' => $pagination ? $pagination->toResponseArray() : null
                ];
                $service_response->setData( $data );
                break;
            case DAOResponseInterface::RECORD_NOT_FOUND :
                $service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
                break;
            case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
                $service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
                break;
        }
        return $service_response;

    }


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

		$service_response = new ServiceResponse();
		$jwtPayload = JWTService::getTokenJWTPayload();
		$user_is_paciente = $jwtPayload->getProfile() === PERFIL_PACIENTE;
		$user_id_paciente = $user_is_paciente ? (new PacienteDAO())->getPacienteIDFromUsuarioID( $jwtPayload->getUid() ) : 0;
		if ($user_is_paciente && $id_pet !== $user_id_paciente) {
			$service_response->setStatus( ServiceResponseInterface::FORBIDDEN );
			return $service_response;
		}
		$log_service = new LogService();
		$consulta_dao = new ConsultaDAO();
		$dao_response = $consulta_dao->getConsultaListByPet( $id_pet, $pagination, $query_filter_collection, $query_order_collection );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
					return $formulario_listing_vm;
				})( $dao_response->getData() );
				$formulario_listing_array = ConsultaMapper::getConsultaListingArrayFromVM( $formulario_listing_vm );
				$pagination = $dao_response->getPagination();
				$data = [ 
					'consultas' => $formulario_listing_array,
					'pagination' => $pagination ? $pagination->toResponseArray() : null
				];
				$service_response->setData( $data );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	public function getConsultaListByPetIDByUnidadeID(int $idPet, int $idUnidade, ?Pagination $pagination, QueryFilterCollection $query_filter_collection,
			QueryOrderCollection $query_order_collection): ServiceResponse {

		$service_response = new ServiceResponse();
		$jwtPayload = JWTService::getTokenJWTPayload();
		$user_is_paciente = $jwtPayload->getProfile() === PERFIL_PACIENTE;
		$user_id_paciente = $user_is_paciente ? (new PacienteDAO())->getPacienteIDFromUsuarioID( $jwtPayload->getUid() ) : 0;
		if ($user_is_paciente && $id_pet !== $user_id_paciente) {
			$service_response->setStatus( ServiceResponseInterface::FORBIDDEN );
			return $service_response;
		}
		$log_service = new LogService();
		$consulta_dao = new ConsultaDAO();
		$dao_response = $consulta_dao->getConsultaListByPetIdByUnidadeID( $idPet, $idUnidade, $pagination, $query_filter_collection, $query_order_collection );
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$formulario_listing_vm = (function (GeneralCollection $formulario_listing_vm): GeneralCollection {
					return $formulario_listing_vm;
				})( $dao_response->getData() );
				$formulario_listing_array = ConsultaMapper::getConsultaListingArrayFromVM( $formulario_listing_vm );
				$pagination = $dao_response->getPagination();
				$data = [ 
					'consultas' => $formulario_listing_array,
					'pagination' => $pagination ? $pagination->toResponseArray() : null
				];
				$service_response->setData( $data );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	private function getWrongRespostaEscolhaOpcao(ConsultaRegistrationViewModel $consulta_registration_vm, GeneralCollection $opcoes_perguntas_vm_collection,
			int &$id_opcao_pergunta_wrong): ?RespostaEscolhaOpcao {

		return $consulta_registration_vm->getRespostaEscolhaOpcaoCollection()
			->find( 
			function (RespostaEscolhaOpcao $resposta_escolha_opcao) use ($opcoes_perguntas_vm_collection, &$id_opcao_pergunta_wrong) {
				return $resposta_escolha_opcao->getResposta()
					->some( 
					function (int $id_opcao_pergunta) use ($resposta_escolha_opcao, $opcoes_perguntas_vm_collection, &$id_opcao_pergunta_wrong): bool {
						$verify_if_option_exists = function (PerguntaOpcoesViewModel $pergunta_opcoes_vm) use ($id_opcao_pergunta, $resposta_escolha_opcao) {
							return $pergunta_opcoes_vm->getIdOpcaoPergunta() !== $id_opcao_pergunta;
						};
						$verify_if_option_belongs_to_question = function (PerguntaOpcoesViewModel $pergunta_opcoes_vm) use ($id_opcao_pergunta,
						$resposta_escolha_opcao) {
							$same_option = $pergunta_opcoes_vm->getIdOpcaoPergunta() === $id_opcao_pergunta;
							$same_question = $pergunta_opcoes_vm->getIdPergunta() === $resposta_escolha_opcao->getIdPergunta();
							return $same_option && !$same_question;
						};
						$option_is_valid = !$opcoes_perguntas_vm_collection->every( $verify_if_option_exists ) &&
						!$opcoes_perguntas_vm_collection->some( $verify_if_option_belongs_to_question );
						if (!$option_is_valid) {
							$id_opcao_pergunta_wrong = $id_opcao_pergunta;
						}
						return !$option_is_valid;
					} );
			} );

	}

	// private function changeQuestionYesOrNoToZeroAndOne (GeneralCollection $pergunta_details_vm_collection, ConsultaRegistrationViewModel
	// $consulta_registration_vm) {
	// if ($pergunta_details_vm_collection->length === 0) {
	// return true;
	// }
	// $pergunta_details_vm_collection->forEach(function (PerguntaDetailsViewModel $pergunta_details_vm) use ($consulta_registration_vm) {
	// if ($pergunta_details_vm->getIdTipoPergunta() === TIPO_PERGUNTA_SIM_OU_NAO) {
	// $resposta_numerica_inteira = (function (RespostaNumericaInteira $rni): RespostaNumericaInteira {
	// return $rni;
	// })($consulta_registration_vm->getRespostaNumericaInteiraCollection()->find(
	// function (RespostaNumericaInteira $resposta_numerica_inteira) use ($pergunta_details_vm): bool {
	// return $resposta_numerica_inteira->getIdPergunta() === $pergunta_details_vm->getIdPergunta();
	// }
	// ));
	//
	// $resposta_numerica_inteira->setResposta((int)!!$resposta_numerica_inteira->getResposta());
	// }
	// });
	// }
	private function getPerguntaErrors(GeneralCollection $wrong_perguntas) {

		$filter_by_error = function (string $error): callable {
			return function (array $pergunta_error) use ($error): bool {
				return $pergunta_error ['error'] === $error;
			};
		};
		$errors = [ ];
		$respostas_obrigatorias = $wrong_perguntas->filter( $filter_by_error( 'required' ) );
		$respostas_tipagem_errada = $wrong_perguntas->filter( $filter_by_error( 'type' ) );
		$mapper = function (array $wrong_resposta): array {
			unset( $wrong_resposta ['error'] );
			return $wrong_resposta;
		};
		if ($respostas_obrigatorias->length) {
			$errors ['respostas_obrigatorias'] = $respostas_obrigatorias->map( $mapper )
				->toArray();
		}
		if ($respostas_tipagem_errada->length) {
			$errors ['respostas_tipagem_errada'] = $respostas_tipagem_errada->map( $mapper )
				->toArray();
		}
		return $errors;

	}

	private function getMissingPerguntaFromConsultaRegistrationVM(ConsultaRegistrationViewModel $consulta_registration_vm,
			GeneralCollection $pergunta_details_vm_collection): GeneralCollection {

		$wrong_perguntas = new GeneralCollection();
		$pergunta_details_vm_collection->forEach( 
			function (PerguntaDetailsViewModel $pergunta_details_vm) use ($consulta_registration_vm, $wrong_perguntas): void {
				$finder = function (RespostaFormularioAbstract $resposta) use ($pergunta_details_vm): bool {
					return $pergunta_details_vm->getIdPergunta() === $resposta->getIdPergunta();
				};
				$resposta_escolha_opcao = $consulta_registration_vm->getRespostaEscolhaOpcaoCollection()
					->find( $finder );
				$resposta_numerica_inteira = $resposta_escolha_opcao ? null : $consulta_registration_vm->getRespostaNumericaInteiraCollection()
					->find( $finder );
				$resposta_numerica_decimal = $resposta_numerica_inteira ? null : $consulta_registration_vm->getRespostaNumericaDecimalCollection()
					->find( $finder );
				$resposta_textual = $resposta_numerica_decimal ? null : $consulta_registration_vm->getRespostaTextualCollection()
					->find( $finder );
				$tipo_pergunta = $pergunta_details_vm->getIdTipoPergunta();
				$resposta_escolha_opcao_allowed_types = [ 
					TIPO_PERGUNTA_CHECKBOX,
					TIPO_PERGUNTA_MULTIPLA_ESCOLHA
				];
				$resposta_numerica_inteira_allowed_types = [ 
					TIPO_PERGUNTA_RESPOSTA_NUMERICA_INTEIRA,
					TIPO_PERGUNTA_SIM_OU_NAO
				];
				$resposta_numerica_decimal_allowed_types = [ 
					TIPO_PERGUNTA_RESPOSTA_NUMERICA_DECIMAL
				];
				$resposta_textual_allowed_types = [ 
					TIPO_PERGUNTA_PARAGRAFO,
					TIPO_PERGUNTA_RESPOSTA_CURTA
				];
				$type_is_wrong = ($resposta_escolha_opcao && !in_array( $tipo_pergunta, $resposta_escolha_opcao_allowed_types )) ||
				($resposta_numerica_inteira && !in_array( $tipo_pergunta, $resposta_numerica_inteira_allowed_types )) ||
				($resposta_numerica_decimal && !in_array( $tipo_pergunta, $resposta_numerica_decimal_allowed_types )) ||
				($resposta_textual && !in_array( $tipo_pergunta, $resposta_textual_allowed_types ));
				if ($type_is_wrong) {
					$wrong_perguntas->push( 
						[ 
							'error' => 'type',
							'id_pergunta' => $pergunta_details_vm->getIdPergunta(),
							'tipo_pergunta_correto' => $pergunta_details_vm->getIdTipoPergunta()
						] );
				} else if ($pergunta_details_vm->isObrigatorio()) {
					$pergunta_not_found = !($resposta_escolha_opcao || $resposta_numerica_inteira || $resposta_numerica_decimal || $resposta_textual);
					if ($pergunta_not_found) {
						$wrong_perguntas->push( [ 
							'error' => 'required',
							'id_pergunta' => $pergunta_details_vm->getIdPergunta()
						] );
					}
				}
			} );
		return $wrong_perguntas;

	}

	public function getConsultaByID(int $id_consulta): ServiceResponse {

		$consulta_dao = new ConsultaDAO();
		$log_service = new LogService();
		$dao_response = $consulta_dao->getConsultaDetailsByConsultaID( $id_consulta );
		$service_response = new ServiceResponse();
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$consulta_details_vm = (function (ConsultaDetailsViewModel $consulta_details_vm): ConsultaDetailsViewModel {
					return $consulta_details_vm;
				})( $dao_response->getData() );
				$service_response->setData( $consulta_details_vm->toArray() );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				break;
			default :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	public function registerConsultaAnamneseAdicional(array $data_post): ServiceResponse {

		$service_response = new ServiceResponse();
		$consulta_registration_vm = ConsultaMapper::getConsultaAnamneseAdicionalRegistrationVMFromArray( $data_post );
		$agendamento_dao = new AgendamentoDAO();
		$jwt_payload = JWTService::getTokenJWTPayload();
		$medicoLinked = $agendamento_dao->medicoIsLinkedToAgendamento( $jwt_payload->getUid(), $consulta_registration_vm->getIdAgendamento() );
		$assistenteLinked = $agendamento_dao->assistenteIsLinkedToAgendamento( $jwt_payload->getUid(), $consulta_registration_vm->getIdAgendamento() );

		if ((!$medicoLinked) && (!$assistenteLinked)) {
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$service_response->setErrors( [ 
				'id_agendamento' => 'Médico ou Assistente não vinculado a esse agendamento.'
			] );
			return $service_response;
		}

		$formulario_dao = new FormularioDAO();
		$formulario_dao_response = $formulario_dao->getPerguntasByIdAgendamento( $consulta_registration_vm->getIdAgendamento(), $data_post );
		$pergunta_details_vm_collection = $formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS ? $this->getGeneralCollectionFromDAOResponse( 
			$formulario_dao_response ) : new GeneralCollection();
		// $this->changeQuestionYesOrNoToZeroAndOne ($pergunta_details_vm_collection, $consulta_registration_vm);
		$wrong_perguntas = $this->getMissingPerguntaFromConsultaRegistrationVM( $consulta_registration_vm, $pergunta_details_vm_collection );
		if ($wrong_perguntas->length > 0) { // Valida as perguntas obrigatórias e as de tipagem errada.
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$errors = $this->getPerguntaErrors( $wrong_perguntas );
			$service_response->setErrors( $errors );
			return $service_response;
		} else {
			$consulta_dao = new ConsultaDAO();
			$consulta_dao_response = $consulta_dao->registerConsultaAnamneseAdicional( $consulta_registration_vm, $data_post );
			$formulario_dao_response = $formulario_dao->getPerguntasOpcoesByIdsPerguntas( $consulta_registration_vm->getRespostaEscolhaOpcaoCollection() );
			if ($formulario_dao_response->getStatus() === DAOResponseInterface::SUCESS) {
				$opcoes_perguntas_vm_collection = $this->getGeneralCollectionFromDAOResponse( $formulario_dao_response );
				$id_opcao_pergunta_wrong = 0;
				$wrong_resposta_escolha_opcao = $this->getWrongRespostaEscolhaOpcao( $consulta_registration_vm, $opcoes_perguntas_vm_collection,
					$id_opcao_pergunta_wrong );
				if ($wrong_resposta_escolha_opcao) {
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( 
						[ 
							'pergunta' => [ 
								'id' => $wrong_resposta_escolha_opcao->getIdPergunta(),
								'id_opcao_pergunta' => $id_opcao_pergunta_wrong
							]
						] );
					return $service_response;
				}
			}

			$consulta_dao_data = $consulta_dao_response->getData();
			switch ($consulta_dao_response->getStatus()) {
				case DAOResponseInterface::SUCESS :
					$service_response->setData( [ 
						"consulta_id" => $consulta_dao_data ["consulta_id"]
					] );
					$service_response->setStatus( ServiceResponseInterface::SUCESS );
					break;
				case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
				case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
					$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
					$service_response->setErrors( $consulta_dao_response->getErrors() );
					break;
				default :
					$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
					break;
			}

			return $service_response;
		}

	}

	public function auditRegisterExameMedicacaoAtendimento(array $data_post): ServiceResponse {

		$service_response = new ServiceResponse();
		$dao = new ConsultaDAO();
		$daoResponse = $dao->auditRegisterExameMedicacaoAtendimento( $data_post );
		$service_response = $this->setServiceResponse( $daoResponse );

		return $service_response;

	}

}