import { AttendanceType, StudentField } from '@studyportals/studentdomain';
import { suite, test } from '@testdeck/mocha';
import * as Moq from 'typemoq';
import { Actor } from '../../interfaces';
import { AnonymousStudentService } from '../../src/application/anonymous-student-service';
import { StudentRepository } from '../../src/domain/student-repository';

@suite()
class AnonymousStudentServiceTest {

	private testInstanceMock: Moq.IMock<AnonymousStudentService>;

	private studentRepositoryMock: Moq.IMock<StudentRepository>;

	private get studentRepository(): StudentRepository {
		return this.studentRepositoryMock.object;
	}

	private get testInstance(): AnonymousStudentService {
		return this.testInstanceMock.object;
	}

	public before(): void {
		this.testInstanceMock = Moq.Mock.ofType(AnonymousStudentService);
		this.testInstanceMock.callBase = true;

		this.studentRepositoryMock = Moq.Mock.ofType<StudentRepository>();

		this.testInstanceMock
			.setup((x) => x['studentRepository'])
			.returns(() => this.studentRepository);

	}

	@test
	public getStudentData_Should_Call_StudentRepository_getStudentData_When_Called(): void {
		// given
		this.studentRepositoryMock.setup((x) => x.getStudentData(Moq.It.isAny()));

		// when
		this.testInstance.getStudentData(Moq.It.isAny());

		// then
		this.studentRepositoryMock.verify((x) => x.getStudentData(Moq.It.isAny()), Moq.Times.once());
	}

	@test
	public async getStudentDataCompleteness_Should_Call_StudentRepository_getStudentDataCompleteness_When_Called(): Promise<void> {
		// given
		this.studentRepositoryMock.setup((x) => x.getStudentData(Moq.It.isAny()));

		// when
		await this.testInstance.getStudentDataCompleteness(Moq.It.isAny());

		// then
		this.studentRepositoryMock.verify((x) => x.getStudentDataCompleteness(Moq.It.isAny()), Moq.Times.once());
	}

	@test
	public async setStudentData_Should_Call_StudentRepository_setStudentData_When_Called(): Promise<void> {
		// given
		const expectedData = {[StudentField.FIRST_NAME]: 'myName'};
		const expectedActor = Actor.AUTOMATION;

		this.studentRepositoryMock.setup((x) => x.setStudentData(Moq.It.isAny(), Moq.It.isAny()));

		// when
		await this.testInstance.setStudentData(expectedData, expectedActor);

		// then
		this.studentRepositoryMock.verify((x) => x.setStudentData(expectedData, expectedActor), Moq.Times.once());
	}

	@test
	public async setStudentData_Should_Call_StudentRepository_setStudentData_With_Default_Actor_User_When_Called(): Promise<void> {
		// given
		const expectedData = {[StudentField.FIRST_NAME]: 'myName'};
		const expectedActor = Actor.USER;

		this.studentRepositoryMock.setup((x) => x.setStudentData(Moq.It.isAny(), Moq.It.isAny()));

		// when
		await this.testInstance.setStudentData(expectedData);

		// then
		this.studentRepositoryMock.verify((x) => x.setStudentData(expectedData, expectedActor), Moq.Times.once());
	}

	@test
	public async setName_Should_Call_StudentRepository_setName_When_Called(): Promise<void> {
		// given
		this.studentRepositoryMock.setup((x) => x.setName(Moq.It.isAny()));

		// when
		await this.testInstance.setName(Moq.It.isAny());

		// then
		this.studentRepositoryMock.verify((x) => x.setName(Moq.It.isAny()), Moq.Times.once());
	}

	@test
	public async setGPA_Should_Call_StudentRepository_setGPA_When_Called(): Promise<void> {
		// given
		this.studentRepositoryMock.setup((x) => x.setGPA(Moq.It.isAny(), Moq.It.isAny()));

		// when
		await this.testInstance.setGPA(Moq.It.isAny(), Moq.It.isAny());

		// then
		this.studentRepositoryMock.verify((x) => x.setGPA(Moq.It.isAny(), Moq.It.isAny()), Moq.Times.once());
	}

	@test
	public async addToCollection_Should_Call_StudentRepository_addToCollection_When_Called(): Promise<void> {
		// given
		this.studentRepositoryMock.setup((x) => x.addToCollection(Moq.It.isAny(), Moq.It.isAny()));

		// when
		await this.testInstance.addToCollection(StudentField.ATTENDANCE, [AttendanceType.ONLINE]);

		// then
		this.studentRepositoryMock.verify((x) => x.addToCollection(Moq.It.isAny(), Moq.It.isAny()), Moq.Times.once());
	}

	@test
	public async removeFromCollection_Should_Call_StudentRepository_addToCollection_When_Called(): Promise<void> {
		// given
		this.studentRepositoryMock.setup((x) => x.removeFromCollection(Moq.It.isAny(), Moq.It.isAny()));

		// when
		await this.testInstance.removeFromCollection(StudentField.INTERESTS_COUNTRIES, [1, 4, 76]);

		// then
		this.studentRepositoryMock.verify((x) => x.removeFromCollection(Moq.It.isAny(), Moq.It.isAny()), Moq.Times.once());
	}
}
