'use strict';

const knex = require('./knex');
const { HttpError } = require('./errors');
const slugify = require('./utils/slugify');

function curateStash(stash) {
	if (!stash) {
		return null;
	}

	const curatedStash = {
		id: stash.id,
		name: stash.name,
		slug: stash.slug,
		primary: stash.primary,
	};

	return curatedStash;
}

function curateStashEntry(stash, user) {
	const curatedStashEntry = {
		user_id: user.id,
		name: stash.name,
		slug: slugify(stash.name),
		public: false,
	};

	return curatedStashEntry;
}

async function fetchStash(stashId, sessionUser) {
	if (!sessionUser) {
		throw new HttpError('You are not authenthicated', 401);
	}

	const stash = await knex('stashes')
		.where({
			id: stashId,
			user_id: sessionUser.id,
		})
		.first();

	if (!stash) {
		throw new HttpError('You are not authorized to access this stash', 403);
	}

	return curateStash(stash);
}

async function fetchStashes(domain, itemId, sessionUser) {
	const stashes = await knex(`stashes_${domain}s`)
		.select('stashes.*')
		.where({
			[`${domain}_id`]: itemId,
			user_id: sessionUser.id,
		})
		.leftJoin('stashes', 'stashes.id', `stashes_${domain}s.stash_id`);

	return stashes.map(stash => curateStash(stash));
}

async function createStash(newStash, sessionUser) {
	if (!sessionUser) {
		throw new HttpError('You are not authenthicated', 401);
	}

	const stash = await knex('stashes')
		.insert(curateStashEntry(newStash, sessionUser))
		.returning('*');

	return curateStash(stash);
}

async function updateStash(stashId, newStash, sessionUser) {
	if (!sessionUser) {
		throw new HttpError('You are not authenthicated', 401);
	}

	const stash = await knex('stashes')
		.where({
			id: stashId,
			user_id: sessionUser.id,
		})
		.update(newStash)
		.returning('*');

	if (!stash) {
		throw new HttpError('You are not authorized to modify this stash', 403);
	}

	return curateStash(stash);
}

async function removeStash(stashId, sessionUser) {
	if (!sessionUser) {
		throw new HttpError('You are not authenthicated', 401);
	}

	const removed = await knex('stashes')
		.where({
			id: stashId,
			user_id: sessionUser.id,
			primary: false,
		})
		.delete();

	if (removed === 0) {
		throw new HttpError('Unable to remove this stash', 400);
	}
}

async function stashActor(actorId, stashId, sessionUser) {
	const stash = await fetchStash(stashId, sessionUser);

	await knex('stashes_actors')
		.insert({
			stash_id: stash.id,
			actor_id: actorId,
		});

	return fetchStashes('actor', actorId, sessionUser);
}

async function stashScene(sceneId, stashId, sessionUser) {
	const stash = await fetchStash(stashId, sessionUser);

	await knex('stashes_scenes')
		.insert({
			stash_id: stash.id,
			scene_id: sceneId,
		});

	return fetchStashes('scene', sceneId, sessionUser);
}

async function stashMovie(movieId, stashId, sessionUser) {
	const stash = await fetchStash(stashId, sessionUser);

	await knex('stashes_movies')
		.insert({
			stash_id: stash.id,
			movie_id: movieId,
		});

	return fetchStashes('movie', movieId, sessionUser);
}

async function unstashActor(actorId, stashId, sessionUser) {
	await knex
		.from('stashes_actors AS deletable')
		.where('deletable.actor_id', actorId)
		.where('deletable.stash_id', stashId)
		.whereExists(knex('stashes_actors') // verify user owns this stash, complimentary to row-level security
			.leftJoin('stashes', 'stashes.id', 'stashes_actors.stash_id')
			.where('stashes_actors.stash_id', knex.raw('deletable.stash_id'))
			.where('stashes.user_id', sessionUser.id))
		.delete();

	return fetchStashes('actor', actorId, sessionUser);
}

async function unstashScene(sceneId, stashId, sessionUser) {
	await knex
		.from('stashes_scenes AS deletable')
		.where('deletable.scene_id', sceneId)
		.where('deletable.stash_id', stashId)
		.whereExists(knex('stashes_scenes') // verify user owns this stash, complimentary to row-level security
			.leftJoin('stashes', 'stashes.id', 'stashes_scenes.stash_id')
			.where('stashes_scenes.stash_id', knex.raw('deletable.stash_id'))
			.where('stashes.user_id', sessionUser.id))
		.delete();

	return fetchStashes('scene', sceneId, sessionUser);
}

async function unstashMovie(movieId, stashId, sessionUser) {
	await knex
		.from('stashes_movies AS deletable')
		.where('deletable.movie_id', movieId)
		.where('deletable.stash_id', stashId)
		.whereExists(knex('stashes_movies') // verify user owns this stash, complimentary to row-level security
			.leftJoin('stashes', 'stashes.id', 'stashes_movies.stash_id')
			.where('stashes_movies.stash_id', knex.raw('deletable.stash_id'))
			.where('stashes.user_id', sessionUser.id))
		.delete();

	return fetchStashes('movie', movieId, sessionUser);
}

module.exports = {
	createStash,
	curateStash,
	removeStash,
	stashActor,
	stashScene,
	stashMovie,
	unstashScene,
	unstashActor,
	unstashMovie,
	updateStash,
};