<?php
declare(strict_types = 1)
	;

namespace App\Services;

use App\DAO\AgendaDAO;
use App\DAO\AgendamentoDAO;
use App\DAO\DAOResponse\DAOResponseInterface;
use App\DAO\Filter\QueryFilter;
use App\Entities\Agenda\Agenda;
use App\Mappers\AgendamentoMapper;
use App\Services\ServiceResponse\ServiceResponse;
use App\Services\ServiceResponse\ServiceResponseInterface;
use App\Utils\Collections\QueryFilterCollection;
use App\Utils\ResponseException;
use App\ViewModels\Agendamento\AgendamentoDetailsViewModel\AgendamentoDetailsViewModel;
use App\ViewModels\Agendamento\AgendamentoInfoViewModel\AgendamentoInfoViewModel;
use App\DAO\AgendamentoVoucherDAO;

// use phpDocumentor\Reflection\DocBlock\Tags\Var_;
class AgendamentoService extends Service {

	public function registerAgendamento(array $agendamento_array): ServiceResponse {

		$agendamento_dao = new AgendamentoDAO();
		$agendamento_registration_vm = AgendamentoMapper::getAgendamentoRegistrationVMFromArray( $agendamento_array );
		$dao_response = $agendamento_dao->persistAgendamentoRegistrationVM( $agendamento_registration_vm );
		$service_response = new ServiceResponse();
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
			case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
				$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
				$service_response->setErrors( $dao_response->getErrors() );
				break;
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$service_response->setData( [ 
					'id_agendamento' => $dao_response->getData()
						->getid()
				] );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	public function registerAgendamentoAnamneseAdcional(array $agendamento_array): ServiceResponse {

		$agendamento_dao = new AgendamentoDAO();
		$agendamento_registration_vm = AgendamentoMapper::getAgendamentoRegistrationVMFromAnamneeseAdicional( $agendamento_array );
		$dao_response = $agendamento_dao->persistAgendamentoRegistrationVM( $agendamento_registration_vm );
		$service_response = new ServiceResponse();
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::FOREIGN_KEY_DONT_EXISTS :
			case DAOResponseInterface::DUPLICATED_UNIQUE_KEY :
				$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
				$service_response->setErrors( $dao_response->getErrors() );
				break;
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				$service_response->setData( [ 
					'id_agendamento' => $dao_response->getData()
						->getid()
				] );
				break;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	public function registerAgendamentoVisaoCliente(array $agendamento_array): ServiceResponse {

		$agenda_dao = new AgendaDAO();
		$dao_response = $agenda_dao->getAgendaByID( ( int ) $agendamento_array ['id_agenda'] );
		$service_response = new ServiceResponse();
		if ($dao_response->getStatus() === DAOResponseInterface::SUCESS) {
			$agenda = (function (Agenda $agenda): Agenda {
				return $agenda;
			})( $dao_response->getData() );
			$operation_allowed = $agenda->getIdTIPOPROCEDIMENTO() === ID_TIPO_PROCEDIMENTO_CONSULTA;
			if ($operation_allowed) {
				$agendamento_array ['id_procedimento'] = ID_PROCEDIMENTO_CONSULTA;
				return $this->registerAgendamento( $agendamento_array );
			} else {
				$service_response->setStatus( ServiceResponseInterface::UNAUTHORIZED );
				$service_response->setErrors( [ 
					'id_tipo_procedimento' => 'Cliente só tem permissão para marcar agenda em horário de consulta.'
				] );
			}
		} else if ($dao_response->getStatus() === DAOResponseInterface::RECORD_NOT_FOUND) {
			$service_response->setStatus( ServiceResponseInterface::VALIDATION_PARAMS_ERROR );
			$service_response->setErrors( [ 
				'id_agenda' => 'Essa agenda não existe.'
			] );
		} else {
			$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
		}
		return $service_response;

	}

	public function cancelAgendamento(int $id_agendamento): ServiceResponse {

		$agendamento_dao = new AgendamentoDAO();
		$service_response = new ServiceResponse();
		$dao_response = $agendamento_dao->getAgendamentoInfoFromIdAgendamento( $id_agendamento );
		if ($dao_response->getStatus() === DAOResponseInterface::SUCESS) {
			$agendamento_info_vm = (function (AgendamentoInfoViewModel $agendamento_info_vm): AgendamentoInfoViewModel {
				return $agendamento_info_vm;
			})( $dao_response->getData() );
			$jwt_payload = JWTService::getTokenJWTPayload();
			if ($jwt_payload->getProfile() === PERFIL_PACIENTE && $jwt_payload->getUid() !== $agendamento_info_vm->getIdUsuario()) {
				// Se o usuário solicitante for um paciente, ele somente pode desmarcar o agendamento se ele mesmo for o paciente
				// do agendamento.
				$service_response->setStatus( ServiceResponseInterface::UNAUTHORIZED );
				return $service_response;
			} else if ($agendamento_info_vm->getIdConsulta()) {
				// Não é possível desmarcar um agendamento já vinculado a uma consulta.
				$service_response->setStatus( ServiceResponseInterface::RECORD_IS_LINKED );
				return $service_response;
			}
		} else if ($dao_response->getStatus() === DAOResponseInterface::RECORD_NOT_FOUND) {
			$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
			return $service_response;
		} else {
			$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
		}

		$dao_response = $agendamento_dao->cancelAgendamento( $id_agendamento );
		$status_service_response = [ 
			DAOResponseInterface::SUCESS => ServiceResponseInterface::SUCESS,
			DAOResponseInterface::RECORD_NOT_FOUND => ServiceResponseInterface::RECORD_NOT_FOUND
		] [$dao_response->getStatus()];
		if (!$status_service_response) {
			$status_service_response = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
		}
		$service_response->setStatus( $status_service_response );
		return $service_response;

	}

    public function cancelAgendamentoTelevet(int $id_agendamento): ServiceResponse {

        $agendamento_dao = new AgendamentoDAO();
        $service_response = new ServiceResponse();
        $dao_response = $agendamento_dao->getAgendamentoInfoFromIdAgendamentoTelevet( $id_agendamento );
        if ($dao_response->getStatus() === DAOResponseInterface::SUCESS) {
            $agendamento_info_vm = (function (AgendamentoInfoViewModel $agendamento_info_vm): AgendamentoInfoViewModel {
                return $agendamento_info_vm;
            })( $dao_response->getData() );
            $jwt_payload = JWTService::getTokenJWTPayload();
            if ($jwt_payload->getProfile() === PERFIL_PACIENTE && $jwt_payload->getUid() !== $agendamento_info_vm->getIdUsuario()) {
                // Se o usuário solicitante for um paciente, ele somente pode desmarcar o agendamento se ele mesmo for o paciente
                // do agendamento.
                $service_response->setStatus( ServiceResponseInterface::UNAUTHORIZED );
                return $service_response;
            } else if ($agendamento_info_vm->getIdConsulta()) {
                // Não é possível desmarcar um agendamento já vinculado a uma consulta.
                $service_response->setStatus( ServiceResponseInterface::RECORD_IS_LINKED );
                return $service_response;
            }
        } else if ($dao_response->getStatus() === DAOResponseInterface::RECORD_NOT_FOUND) {
            $service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
            return $service_response;
        } else {
            $service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
        }

        $dao_response = $agendamento_dao->cancelAgendamentoTelevet( $id_agendamento );
        $status_service_response = [
            DAOResponseInterface::SUCESS => ServiceResponseInterface::SUCESS,
            DAOResponseInterface::RECORD_NOT_FOUND => ServiceResponseInterface::RECORD_NOT_FOUND
        ] [$dao_response->getStatus()];
        if (!$status_service_response) {
            $status_service_response = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
        }
        $service_response->setStatus( $status_service_response );
        return $service_response;

    }

	public function updateAgendamento(int $id_agendamento, array $data): ServiceResponse {

		try {
			$agendamento_update_vm = AgendamentoMapper::getAgendamentoUpdateVMFromArray( $data );
		} catch ( ResponseException $exception ) {
			return ServiceResponse::builder()->setStatus( ServiceResponseInterface::INSUFFICIENT_DATA )
				->build();
		}
		$agendamento_dao = new AgendamentoDAO();
		$dao_response = $agendamento_dao->updateAgendamento( $id_agendamento, $agendamento_update_vm );
		$service_response = new ServiceResponse();
		switch ($dao_response->getStatus()) {
			case DAOResponseInterface::SUCESS :
				$service_response->setStatus( ServiceResponseInterface::SUCESS );
				break;
			case DAOResponseInterface::RECORD_NOT_FOUND :
				$service_response->setStatus( ServiceResponseInterface::RECORD_NOT_FOUND );
				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;
			default :
				$service_response->setStatus( ServiceResponseInterface::DATABASE_CONNECTION_ERROR );
				break;
		}
		return $service_response;

	}

	public function getAgendamento(QueryFilter $query_filter): ServiceResponse {

		$assistente_dao = new AgendamentoDAO();
		$query_filter_collection = new QueryFilterCollection();
		$query_filter_collection->push( $query_filter );
		$dao_response = $assistente_dao->getAgendamento( $query_filter_collection );
		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;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response_status = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
				break;
		}
		$service_response = ServiceResponse::builder()->setStatus( $service_response_status )
			->build();
		if ($service_response_status === DAOResponseInterface::SUCESS) {
			$assistente_details_vm = (function (AgendamentoDetailsViewModel $assistente_details_vm): AgendamentoDetailsViewModel {
				return $assistente_details_vm;
			})( $dao_response->getData() );
			$service_response->setData( $assistente_details_vm->toArray() );
		}
		return $service_response;

	}

	public function getAgendamentoSala($id_requisicao_procedimento): ServiceResponse {

		$assistente_dao = new AgendamentoDAO();
		$query_filter_collection = new QueryFilterCollection();
		$query_filter_collection->push( $id_requisicao_procedimento );
		$dao_response = $assistente_dao->getAgendamentoSala( $id_requisicao_procedimento );
		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;
			case DAOResponseInterface::DATABASE_CONNECTION_ERROR :
				$service_response_status = ServiceResponseInterface::DATABASE_CONNECTION_ERROR;
				break;
		}
		$service_response = ServiceResponse::builder()->setStatus( $service_response_status )
			->build();
		if ($service_response_status === DAOResponseInterface::SUCESS) {
			$service_response->setData( $dao_response->getData() );
		}
		return $service_response;

	}

	public function getVoucherIdByAgendamentoId(int $id_agendamento): ServiceResponse {

		$agendamendoVoucher_dao = new AgendamentoVoucherDAO();
		$daoResponse = $agendamendoVoucher_dao->getVoucherIdByAgendamentoId($id_agendamento);
		$service_response = new ServiceResponse();
		$service_response = $this->setServiceResponse($daoResponse);
		return $service_response;

	}

}
