const Images = require('../modules/images');
const Logger = require('../modules/logger');
const Messages = require('../models/message');
const Mongoose = require('mongoose');	 

const ProfileSchema = new Mongoose.Schema({
	"order" : { type: Number, default: 0 },
	"details": {
		"about": { type: String },
		"age": { type: Number, index: true, default: 0 },
		"body": { type: String, enum: ['dns','slim','toned','average','muscular','large','stocky'], default: 'dns' },
		"ethnicity": { type: String, enum: ['dns','asian','black','latino','middle eastern','mixed','native american','white','south asian','other'], default: 'dns' },
		"gender": { type: String, enum: ['man','cis man','trans man','woman','cis woman','trans woman','non-binary','non-conforming','queer','crossdresser'] },
		"height": { type: String },
		"looking": [{ type: String, enum: ['chat','friends','networking','dates','relationship','right now'] }],
		"name": { type: String, index: true },
		"pic": {
			"detail": { type: String, default: "profile/default_detail.png" },
			"thumb": { type: String, default: "profile/default_thumbnail.png" }
		},
		"position": { type: String, enum: ['dns','bottom','vers bottom','versatile','vers top','top'], default: 'dns' },
		"pronouns": { type: String },
		"weight": { type: Number },
		"relationship": { type: String, enum: ['dns','committed','dating','engaged','exclusive','married','open relationship','partnered','single'], default: 'dns' },
		"status": { type: String, enum: ['dns','unknown','negative','negative, on prep','postive','positive, undetectable'], default: 'dns' },
		"tested": { type: Date },
		"tribe": [{ type: String, enum: ['twink','trans','poz','leather','geek','discreet','otter','bear','daddy','jock','clean-cut'] }]
	},
	"messages" : [ { type: Messages.schema } ]
});

ProfileSchema.pre('findOneAndUpdate', function (next) {
	var cnt = 0
	var pic;

	if (this.details && this.details.pic) {
		pic = this.details.pic;
		cnt = cnt + (typeof pic.detail === 'object' ? 1 : 0) + (typeof pic.thumb === 'object' ? 1 : 0);
	}		 

	if (cnt > 0) {
		if (typeof pic.detail === 'object') {
			Images.saveProfileDetailImage(pic.detail, (err, filename) => {
				if (err) {
					Logger.error('[MessageSchema.pre(save)] There was an error processing the message image. [' + err + ']', { error: err });
				}
			
				if (filename) {
					pic.detail = filename;
					cnt -= 1;
					if (cnt === 0) next();
				}
			});
		} 
		
		if (typeof pic.thumb === 'object') {
			Images.saveProfileThumbnailImage(pic.thumb, (err, filename) => {
				if (err) {
					Logger.error('[MessageSchema.pre(save)] There was an error processing the message image. [' + err + ']', { error: err });
				}
			
				if (filename) {
					pic.thumb = filename;
					cnt -= 1;
					if (cnt === 0) next();
				}
			});
		} 
	} else {
		next();
	}
});

ProfileSchema.pre('save', function (next) {
	var cnt = 0;
	var pic;

	if (this.details && this.details.pic) {
		pic = this.details.pic
		cnt = cnt + (typeof pic.detail === 'object' ? 1 : 0) + (typeof pic.thumb === 'object' ? 1 : 0);
	}		 

	if (cnt > 0) {
		if (typeof pic.detail === 'object') {
			Images.saveProfileDetailImage(pic.detail, (err, filename) => {
				if (err) {
					Logger.error('[MessageSchema.pre(save)] There was an error processing the message image. [' + err + ']', { error: err });
				}
			
				if (filename) {
					pic.detail = filename;
					cnt -= 1;
					if (cnt === 0) next();
				}
			});
		} 
		
		if (typeof pic.thumb === 'object') {
			Images.saveProfileThumbnailImage(pic.thumb, (err, filename) => {
				if (err) {
					Logger.error('[MessageSchema.pre(save)] There was an error processing the message image. [' + err + ']', { error: err });
				}
			
				if (filename) {
					pic.thumb = filename;
					cnt -= 1;
					if (cnt === 0) next();
				}
			});
		} 
	} else {
		next();
	}
});

const ProfileModel = Mongoose.model('profiles', ProfileSchema);

function getChatImages (profileId, match, callback) {
  callback = callback || (typeof match === 'function' ? match : function(){});
  match = typeof match === 'object' ? match : {};
  match['messages.image'] = { $exists: true };

  ProfileModel
    .aggregate([
      { $match: { _id: Mongoose.Types.ObjectId(profileId), 'messages.image': { $exists: true } } },
      { $unwind: '$messages' },
      { $match: match },
      { $replaceRoot: { newRoot: '$messages' } }
    ])
    .project('image -_id')
    .exec(callback);
}

module.exports = {	
	
	all: (e) => {
		const promise = new Promise((resolve, reject) => {
			ProfileModel
				.find({})
				.sort({ order: 1 })
				.populate({
					path: 'messages',
					select: 'text image isUser timestamp',
					options: { sort: { timestamp: 1 } }
				})
				.exec((err, result) => {
					if (err) {
						reject(err);
					}

					if (result) {
						resolve(result);
					}
				});
		});

		promise.then((result) => {
			e.emit('all', null, result);
		})
		.catch((err) => {
			e.emit('all', err, null);
		});
	},

	allMessages: (e, profileId) => {
		const promise = new Promise((resolve, reject) => {	
			ProfileModel
			  .find({ _id: profileId })
			  .select('messages')
			  .populate({
			    path: 'messages',
			    select: 'text image isUser timestamp',
			    options: { sort: { timestamp: 1 } }
			  })
			  .exec((err, result) => {
          if (err) {
            reject(err);
          }

          if (result) {
            resolve(result.messages || []);
          }
        });
		});

		promise.then((result) => {
			e.emit('allMessages', null, result);
		})
		.catch((err) => {
			e.emit('allMessages', err, null);
		});
	},

	allChatImages: (e, profileId) => {
		const promise = new Promise((resolve, reject) => {	
      getChatImages(profileId, (err, result) => {
        if (err) {
          reject(err);
        }
        
        if (result) {
          resolve(result);
        }              
      });			
		});

		promise.then((result) => {
			e.emit('allChatImages', null, result);
		})
		.catch((err) => {
			e.emit('allChatImages', err, null);
		});
	},

	allChatImagesReceived: (e, profileId) => {
		const promise = new Promise((resolve, reject) => {	
      getChatImages(profileId, { 'messages.isUser': true }, (err, result) => {
        if (err) {
          reject(err);
        }
        
        if (result) {
          resolve(result);
        }              
      });			
		});

		promise.then((result) => {
			e.emit('allChatImagesReceived', null, result);
		})
		.catch((err) => {
			e.emit('allChatImagesReceived', err, null);
		});
	},

	allChatImagesSent: (e, profileId) => {
		const promise = new Promise((resolve, reject) => {	
      getChatImages(profileId, { 'messages.isUser': false }, (err, result) => {
        if (err) {
          reject(err);
        }
        
        if (result) {
          resolve(result);
        }              
      });			
		});

		promise.then((result) => {
			e.emit('allChatImagesSent', null, result);
		})
		.catch((err) => {
			e.emit('allChatImagesSent', err, null);
		});
	},

	create: (e, profiles) => {
		var count = profiles.length;
		var errors = [];
		var results = [];
		const promise = new Promise((resolve, reject) => {	
			for (let i = 0; i < profiles.length; i++) {
				var profile = profiles[i];
				var profileInstance = new ProfileModel(profile);

				profileInstance.save((err, result) => {
					if (err) {
						count -= 1;
						errors.push({
							profile: profile,
							error: err
						});
						if (count === 0) {
							reject({ results: results, errors: errors });
						}
					}

					if (result) {
						count -= 1;
						results.push(result);
						if (count === 0) {
							resolve({ results: results, errors: errors });
						}
					}
				});
			
			}

		});

		promise.then((result) => {
			e.emit('create', null, result);
		})
		.catch((err) => {
			e.emit('create', err, null);
		});
	},
	
	delete: (e, id) => {
		const promise = new Promise((resolve, reject) => {
			ProfileModel.remove({ _id: id }, (err, result) => {
				if (err) {
					reject(err);
				}

				if (result) {
					resolve(result);
				}
			});
		});

		promise.then((result) => {
			e.emit('delete', null, result);
		})
		.catch((err) => {
			e.emit('delete', err, null);
		});
	},

	deleteMessage: (e, profileId, messageId) => {
		const promise = new Promise((resolve, reject) => {	
			ProfileModel.findById(profileId, (err, profile) => {
				if (err) {
					reject(err);
				}

				if (profile) {
					let message = profile.messages.id(messageId);
					
					if (message) {
						message.remove();
						profile.save((err, result) => {
							if (err) {
								reject(err);
							}
							
							if (result) {
								resolve(result);
							}
						});
					} else {
						reject('The specified message does not exist');
					}
				}
			});
		});

		promise.then((result) => {
			e.emit('deleteMessage', null, result);
		})
		.catch((err) => {
			e.emit('deleteMessage', err, null);
		});
	},

	find: (e, find) => {
		const promise = new Promise((resolve, reject) => {	
			var query = ProfileModel
				.find(find.find)
				.skip(find.options.skip)
				.limit(find.options.limit)
				.sort(find.options.sort)
				.select(find.select || '');

			if (!find.select || (find.select.length && find.select.indexOf('messages'))) {
				query.populate({
					path: 'messages',
					select: 'order text image isUser',
					options: { sort: { order: 1 } }
				});
			}
			
			query.exec((err, results) => {
				if (err) {
					reject(err);
				}

				if (results) {
					resolve(results);
				}
			});
		});

		promise.then((result) => {
			e.emit('find', null, result);
		})
		.catch((err) => {
			e.emit('find', err, null);
		});
	},
		
	get: (e, profileId) => {
		const promise = new Promise((resolve, reject) => {	
			ProfileModel.findById(profileId, (err, result) => {
				if (err) {
					reject(err);
				}

				if (result) {
					resolve(result);
				}
			});
		});

		promise.then((result) => {
			e.emit('get', null, result);
		})
		.catch((err) => {
			e.emit('get', err, null);
		});
	},
	
	getMessage: (e, prodileId, messageId) => {
		const promise = new Promise((resolve, reject) => {	
			ProfileModel.findById(prodileId, (err, result) => {
				if (err) {
					reject(err);
				}

				if (result) {
					let message = result.messages.id(messageId);
					resolve(message ? message : {});
				}
			});
		});

		promise.then((result) => {
			e.emit('getMessage', null, result);
		})
		.catch((err) => {
			e.emit('getMessage', err, null);
		});
	},
	
	update: (e, profileId, profile) => {
		const promise = new Promise((resolve, reject) => {
			ProfileModel.findOneAndUpdate(
				{ _id: profileId }, 
				{ $set: profile },
				{ new: true }, 
				(err, result) => {
					if (err) {
						reject(err);
					}

					if (result) {
						resolve(result);
					}
				});
		});

		promise.then((result) => {
			e.emit('update', null, result);
		})
		.catch((err) => {
			e.emit('update', err, null);
		});
	},
	
	updateMessage: (e, profileId, messageId, data) => {
		const promise = new Promise((resolve, reject) => {
			ProfileModel.findOneAndUpdate(
				{ _id: profileId, 'messages._id': messageId }, 
				{ $set: { 'messages.$': data } },
				{ new: true }, 
				(err, result) => {
					if (err) {
						reject(err);
					}

					if (result) {
						resolve(result);
					}
				});
		});

		promise.then((result) => {
			e.emit('updateMessage', null, result);
		})
		.catch((err) => {
			e.emit('updateMessage', err, null);
		});
	}
};
