// provides a request class for handling the PUT /streams/close request,
// for users to "close" streams (for themselves) 

'use strict';

const RestfulRequest = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/lib/util/restful/restful_request');
const ModelSaver = require(process.env.CSSVC_BACKEND_ROOT + '/api_server/lib/util/restful/model_saver');

class CloseRequest extends RestfulRequest {

	// authorize the current user against the request
	async authorize () {
		// closing of streams is deprecated
		throw this.errorHandler.error('deprecated');
		
		// get the stream
		this.stream = await this.data.streams.getById(this.request.params.id);
		if (!this.stream) {
			throw this.errorHandler.error('notFound', { info: 'stream' });
		}
        
		// only direct streams can be closed
		if (this.stream.get('type') !== 'direct') {
			throw this.errorHandler.error('updateAuth', { reason: 'only direct streams can be closed' });
		}

		const authorized = await this.request.user.authorizeStream(this.request.params.id, this);
		if (!authorized) {
			throw this.errorHandler.error('updateAuth', { reason: 'only members can close this stream' });
		}
	}

	// process the request...
	async process () {
		// update the user's preferences to indicate the stream is "closed"
		const op = {
			$set: {
				[`preferences.closedStreams.${this.stream.id}`]: true,
				modifiedAt: Date.now()
			}
		};
		this.transforms.updateOp = await new ModelSaver({
			request: this.request,
			collection: this.data.users,
			id: this.user.id
		}).save(op);
	}

	// form the response to the request
	async handleResponse () {
		if (this.gotError) {
			return super.handleResponse();
		}
		this.responseData = {
			user: this.transforms.updateOp,
			stream: {	// note, this stream update only applies for the current user
				_id: this.stream.id,	// DEPRECATE ME
				id: this.stream.id,
				$set: {
					isClosed: true
				}
			}
		};
		await super.handleResponse();
	}

	// after the response is sent...
	async postProcess () {
		// send message on the user's channel
		const channel = `user-${this.user.id}`;
		const message = Object.assign({}, this.responseData, { requestId: this.request.id });
		try {
			await this.api.services.broadcaster.publish(
				message,
				channel,
				{ request: this }
			);
		}
		catch (error) {
			// this doesn't break the chain, but it is unfortunate...
			this.request.warn(`Could not publish preferences update message to user ${this.user.id}: ${JSON.stringify(error)}`);
		}
	}

	// describe this route for help
	static describe () {
		return {
			tag: 'close',
			summary: 'Close a direct stream for the current user',
			access: 'User must be a member of the stream',
			description: 'Set the indicated direct stream as closed for the current user. This is really an update to the user\'s preferences, not the stream itself.',
			input: 'Specify the stream ID in the path',
			returns: {
				summary: 'A user directive indicating how to update the user preferences, and a stream directive indicating to set the "isClosed" flag on the stream. Note that the stream update does not reflect a global change to the stream object, it only applies for the current user.',
				looksLike: {
					user: '<Directive to update the user preferences>',
					stream: '<Directive to set isClosed for the stream>'
				}
			},
			publishes: 'Same as the response, sent on the user channel for the user',
			errors: [
				'updateAuth'
			]
		};
	}
}

module.exports = CloseRequest;
