'use strict';

var validator = require('validator');
var _ = require('lodash');

var db = require('../database');
var meta = require('../meta');
var topics = require('../topics');
var user = require('../user');
var privileges = require('../privileges');
var plugins = require('../plugins');
var pubsub = require('../pubsub');
var utils = require('../utils');
var translator = require('../translator');

module.exports = function (Posts) {
	pubsub.on('post:edit', function (pid) {
		require('./cache').del(pid);
	});

	Posts.edit = async function (data) {
		const canEdit = await privileges.posts.canEdit(data.pid, data.uid);
		if (!canEdit.flag) {
			throw new Error(canEdit.message);
		}
		let postData = await Posts.getPostData(data.pid);
		if (!postData) {
			throw new Error('[[error:no-post]]');
		}

		const oldContent = postData.content; // for diffing purposes
		postData.content = data.content;
		postData.edited = Date.now();
		postData.editor = data.uid;
		if (data.handle) {
			postData.handle = data.handle;
		}
		const result = await plugins.fireHook('filter:post.edit', { req: data.req, post: postData, data: data, uid: data.uid });
		postData = result.post;

		const [editor, topic] = await Promise.all([
			user.getUserFields(data.uid, ['username', 'userslug']),
			editMainPost(data, postData),
		]);

		await Posts.setPostFields(data.pid, postData);

		if (meta.config.enablePostHistory === 1) {
			await Posts.diffs.save(data.pid, oldContent, data.content);
		}
		await Posts.uploads.sync(data.pid);

		postData.cid = topic.cid;
		postData.topic = topic;

		await topics.notifyFollowers(postData, data.uid, {
			type: 'post-edit',
			bodyShort: translator.compile('notifications:user_edited_post', editor.username, postData.topic.title),
			nid: 'edit_post:' + postData.pid + ':uid:' + data.uid,
		});

		plugins.fireHook('action:post.edit', { post: _.clone(postData), data: data, uid: data.uid });

		require('./cache').del(String(postData.pid));
		pubsub.publish('post:edit', String(postData.pid));

		postData = await Posts.parsePost(postData);

		return {
			topic: topic,
			editor: editor,
			post: postData,
		};
	};

	async function editMainPost(data, postData) {
		const tid = postData.tid;
		const title = data.title ? data.title.trim() : '';

		const [topicData, isMain] = await Promise.all([
			topics.getTopicFields(tid, ['cid', 'title', 'timestamp']),
			Posts.isMain(data.pid),
		]);

		if (!isMain) {
			return {
				tid: tid,
				cid: topicData.cid,
				title: validator.escape(String(topicData.title)),
				isMainPost: false,
				renamed: false,
			};
		}

		const newTopicData = {
			tid: tid,
			cid: topicData.cid,
			uid: postData.uid,
			mainPid: data.pid,
		};
		if (title) {
			newTopicData.title = title;
			newTopicData.slug = tid + '/' + (utils.slugify(title) || 'topic');
		}
		newTopicData.thumb = data.thumb || '';

		data.tags = data.tags || [];

		if (data.tags.length) {
			const canTag = await privileges.categories.can('topics:tag', topicData.cid, data.uid);
			if (!canTag) {
				throw new Error('[[error:no-privileges]]');
			}
		}
		const results = await plugins.fireHook('filter:topic.edit', { req: data.req, topic: newTopicData, data: data });
		await db.setObject('topic:' + tid, results.topic);
		await topics.updateTopicTags(tid, data.tags);
		const tags = await topics.getTopicTagsObjects(tid);

		newTopicData.tags = data.tags;
		newTopicData.oldTitle = topicData.title;
		newTopicData.timestamp = topicData.timestamp;
		const renamed = translator.escape(validator.escape(String(title))) !== topicData.title;
		plugins.fireHook('action:topic.edit', { topic: newTopicData, uid: data.uid });
		return {
			tid: tid,
			cid: newTopicData.cid,
			uid: postData.uid,
			title: validator.escape(String(title)),
			oldTitle: topicData.title,
			slug: newTopicData.slug,
			isMainPost: true,
			renamed: renamed,
			tags: tags,
		};
	}
};
