
'use strict';

var async = require('async'),
	validator = require('validator'),
	db = require('../database'),
	utils = require('../../public/src/utils'),
	plugins = require('../plugins'),
	user = require('../user'),
	meta = require('../meta'),
	posts = require('../posts'),
	threadTools = require('../threadTools'),
	postTools = require('../postTools'),
	privileges = require('../privileges'),
	categories = require('../categories');

module.exports = function(Topics) {

	Topics.create = function(data, callback) {
		var uid = data.uid,
			title = data.title,
			cid = data.cid;

		db.incrObjectField('global', 'nextTid', function(err, tid) {
			if (err) {
				return callback(err);
			}

			var slug = utils.slugify(title),
				timestamp = Date.now();

			if (!slug.length) {
				return callback(new Error('[[error:invalid-title]]'));
			}

			slug = tid + '/' + slug;

			var topicData = {
				'tid': tid,
				'uid': uid,
				'cid': cid,
				'mainPid': 0,
				'title': title,
				'slug': slug,
				'timestamp': timestamp,
				'lastposttime': 0,
				'postcount': 0,
				'viewcount': 0,
				'locked': 0,
				'deleted': 0,
				'pinned': 0
			};

			if (data.thumb) {
				topicData.thumb = data.thumb;
			}

			db.setObject('topic:' + tid, topicData, function(err) {
				if (err) {
					return callback(err);
				}

				async.parallel([
					function(next) {
						db.sortedSetsAdd(['topics:tid', 'categories:' + cid + ':tid'], timestamp, tid, next);
					},
					function(next) {
						user.addTopicIdToUser(uid, tid, timestamp, next);
					},
					function(next) {
						db.incrObjectField('category:' + cid, 'topic_count', next);
					},
					function(next) {
						db.incrObjectField('global', 'topicCount', next);
					},
					function(next) {
						Topics.createTags(data.tags, tid, timestamp, next);
					}
				], function(err) {
					if (err) {
						return callback(err);
					}
					plugins.fireHook('action:topic.save', tid);
					callback(null, tid);
				});
			});
		});
	};

	Topics.post = function(data, callback) {
		var uid = data.uid,
			title = data.title,
			content = data.content,
			cid = data.cid;

		if (title) {
			title = title.trim();
		}

		if (!title || title.length < parseInt(meta.config.minimumTitleLength, 10)) {
			return callback(new Error('[[error:title-too-short, ' + meta.config.minimumTitleLength + ']]'));
		} else if(title.length > parseInt(meta.config.maximumTitleLength, 10)) {
			return callback(new Error('[[error:title-too-long, ' + meta.config.maximumTitleLength + ']]'));
		}

		async.waterfall([
			function(next) {
				categories.exists(cid, next);
			},
			function(categoryExists, next) {
				if (!categoryExists) {
					return next(new Error('[[error:no-category]]'));
				}
				privileges.categories.can('topics:create', cid, uid, next);
			},
			function(canCreate, next) {
				if(!canCreate) {
					return next(new Error('[[error:no-privileges]]'));
				}
				user.isReadyToPost(uid, next);
			},
			function(next) {
				plugins.fireHook('filter:topic.post', data, next);
			},
			function(filteredData, next) {
				content = filteredData.content || data.content;
				Topics.create({uid: uid, title: title, cid: cid, thumb: data.thumb, tags: data.tags}, next);
			},
			function(tid, next) {
				Topics.reply({uid:uid, tid:tid, content:content, req: data.req}, next);
			},
			function(postData, next) {
				async.parallel({
					postData: function(next) {
						next(null, postData);
					},
					settings: function(next) {
						user.getSettings(uid, function(err, settings) {
							if (err) {
								return next(err);
							}
							if (settings.followTopicsOnCreate) {
								threadTools.follow(postData.tid, uid, next);
							} else {
								next();
							}
						});
					},
					topicData: function(next) {
						Topics.getTopicsByTids([postData.tid], 0, next);
					}
				}, next);
			},
			function(data, next) {
				if(!Array.isArray(data.topicData) || !data.topicData.length) {
					return next(new Error('[[error:no-topic]]'));
				}

				data.topicData = data.topicData[0];
				data.topicData.unreplied = 1;

				plugins.fireHook('action:topic.post', data.topicData);

				next(null, {
					topicData: data.topicData,
					postData: data.postData
				});
			}
		], callback);
	};

	Topics.reply = function(data, callback) {
		var tid = data.tid,
			uid = data.uid,
			toPid = data.toPid,
			content = data.content,
			postData;

		async.waterfall([
			function(next) {
				async.parallel({
					exists: function(next) {
						threadTools.exists(tid, next);
					},
					locked: function(next) {
						Topics.isLocked(tid, next);
					},
					canReply: function(next) {
						privileges.topics.can('topics:reply', tid, uid, next);
					}
				}, next);
			},
			function(results, next) {
				if (!results.exists) {
					return next(new Error('[[error:no-topic]]'));
				}
				if (results.locked) {
					return next(new Error('[[error:topic-locked]]'));
				}
				if (!results.canReply) {
					return next(new Error('[[error:no-privileges]]'));
				}

				user.isReadyToPost(uid, next);
			},
			function(next) {
				plugins.fireHook('filter:topic.reply', data, next);
			},
			function(filteredData, next) {
				content = filteredData.content || data.content;
				if (content) {
					content = content.trim();
				}

				if (!content || content.length < parseInt(meta.config.miminumPostLength, 10)) {
					return callback(new Error('[[error:content-too-short, '  + meta.config.minimumPostLength + ']]'));
				}

				posts.create({uid:uid, tid:tid, content:content, toPid:toPid}, next);
			},
			function(data, next) {
				postData = data;
				Topics.markAsUnreadForAll(tid, next);
			},
			function(next) {
				Topics.markAsRead([tid], uid, next);
			},
			function(next) {
				async.parallel({
					userInfo: function(next) {
						posts.getUserInfoForPosts([postData.uid], next);
					},
					topicInfo: function(next) {
						Topics.getTopicFields(tid, ['tid', 'title', 'slug', 'cid'], next);
					},
					settings: function(next) {
						user.getSettings(uid, next);
					},
					postIndex: function(next) {
						posts.getPidIndex(postData.pid, uid, next);
					},
					content: function(next) {
						postTools.parse(postData.content, next);
					}
				}, next);
			},
			function(results, next) {
				postData.user = results.userInfo[0];
				results.topicInfo.title = validator.escape(results.topicInfo.title);
				postData.topic = results.topicInfo;
				postData.content = results.content;

				if (results.settings.followTopicsOnReply) {
					threadTools.follow(postData.tid, uid);
				}
				postData.index = results.postIndex - 1;
				postData.favourited = false;
				postData.votes = 0;
				postData.display_moderator_tools = true;
				postData.display_move_tools = true;
				postData.selfPost = false;
				postData.relativeTime = utils.toISOString(postData.timestamp);

				if (parseInt(uid, 10)) {
					Topics.notifyFollowers(tid, postData.pid, uid);

					user.notifications.sendPostNotificationToFollowers(uid, tid, postData.pid);
				}

				next(null, postData);
			}
		], callback);
	};

};
