import { IEventAggregationService, ISubscriber } from "@studyportals/event-aggregation-service-interface";
import { ITokenBasedSessionService,	SessionCreatedEvent } from '@studyportals/student-interfaces';
import { IStudent, StudentField } from '@studyportals/studentdomain';
import { Actor, AnonymousStudentProfileSynced, InterestType, StudentRepositoryStateType } from '../../../interfaces';
import { CatchReportAsyncException, CatchReportException } from '../../decorators/error-decorators';
import { AnonymousStudentEventBroadcaster } from '../../infrastructure/anonymous-student-event-broadcaster';
import { LocalStudentClient } from '../../infrastructure/clients/local-student-client';
import { WriteHistoryRecord } from '../dto/write-history-record';
import { StudentRepository } from '../student-repository';
import { StudentRepositoryState } from './student-repository-state';

export class OfflineStudentRepositoryState extends StudentRepositoryState implements ISubscriber<SessionCreatedEvent> {

	private studentClient: LocalStudentClient;
	private anonymousStudentEventBroadcaster: AnonymousStudentEventBroadcaster;

	constructor(
		protected eventAggregationService: IEventAggregationService,
		protected sessionService: ITokenBasedSessionService,
		protected studentRepository: StudentRepository
	) {
		super(StudentRepositoryStateType.OFFLINE, eventAggregationService, sessionService, studentRepository);
		this.anonymousStudentEventBroadcaster = studentRepository.anonymousStudentEventBroadcaster;
		this.studentClient = new LocalStudentClient('AnonymousStudent/Offline', 2629800, this.anonymousStudentEventBroadcaster);
	}

	@CatchReportException
	public initialize(): void {
		this.eventAggregationService.subscribeTo(SessionCreatedEvent.EventType, this);
	}

	@CatchReportAsyncException
	public async notify(sessionCreatedEvent: SessionCreatedEvent): Promise<void> {
		const onlineState = this.studentRepository.onlineState;

		await this.syncData();
		this.studentRepository.updateState(onlineState);

		const event = new AnonymousStudentProfileSynced(new Date(), StudentRepositoryStateType.ONLINE);
		this.anonymousStudentEventBroadcaster.broadcastStudentProfileSyncedEvent(event);
	}

	public async setStudentData(studentData: IStudent, actor: Actor): Promise<void> {
		const studentFields = Object.keys(studentData) as StudentField[];

		await this.studentClient.addToWriteHistory(studentFields, actor);
		await this.studentClient.setData(studentData);
	}

	public async getStudentData(studentFields: StudentField[]): Promise<IStudent> {
		return this.studentClient.getData(studentFields);
	}

	public async addToCollection(type: StudentField, items: any[]): Promise<void> {
		return this.studentClient.addToCollection(type, items);
	}

	public async removeFromCollection(type: StudentField, items: any[]): Promise<void> {
		return this.studentClient.removeFromCollection(type, items);
	}

	public async syncData(): Promise<void> {
		await this.studentRepository.offlineToOnlineSynchronizationService.syncData();
		await this.studentClient.cleanUp();
	}

	public async getWriteHistory(): Promise<WriteHistoryRecord[]> {
		return this.studentClient.getWriteHistory();
	}
}
