import { Injectable } from '@nestjs/common' import { isNil } from 'lodash' import { Appointment, Patient, User } from '../../../models' import { AppointmentRepository } from '../../../repositories/appointment.repository' import { BusinessExceptionError, NotFoundError, RequiredArgumentError } from '../../../errors' import { Vonage } from '../../../services/vonage' @Injectable() export class VideoCall { constructor(private readonly appointmentRepository: AppointmentRepository, private readonly vonage: Vonage) {} async enterVideocall(requester: Patient | User, appointmentId: string): Promise { if (isNil(requester)) throw new RequiredArgumentError('requester') const appointment = await this.getAppointment(appointmentId) if (appointment.isCancelled) throw new BusinessExceptionError('Appointment is cancelled') if (appointment.isConsultationFinished) throw new BusinessExceptionError('Appointment is already finished') if (appointment.state === 'in_consultation') return appointment if (requester instanceof User && appointment.state === 'user_waiting') return appointment if (requester instanceof Patient) { if (appointment.state === 'patient_waiting') return appointment return this.registerPatientArrived(appointment) } return this.generateSession(appointment) } private async generateSession(appointment: Appointment): Promise { appointment.video_session = await this.vonage.createSession() appointment.patient_video_token = await this.vonage.generateToken(appointment.video_session) appointment.user_video_token = await this.vonage.generateToken(appointment.video_session) appointment.state = appointment.state === 'patient_waiting' ? 'in_consultation' : 'user_waiting' await this.appointmentRepository.save(appointment, [ 'state', 'video_session', 'patient_video_token', 'user_video_token', ]) return appointment } private async registerPatientArrived(appointment: Appointment): Promise { appointment.patient_arrived_at = new Date() appointment.state = appointment.state === 'user_waiting' ? 'in_consultation' : 'patient_waiting' await this.appointmentRepository.save(appointment, ['state', 'patient_arrived_at']) return appointment } private async getAppointment(appointmentId: string): Promise { const appointment = await this.appointmentRepository.get(appointmentId) if (isNil(appointment)) throw new NotFoundError('Appointment not found') return appointment } }